Pasar nombres de clases para reaccionar componentes

98

Estoy tratando de pasar un nombre de clase a un componente de reacción para cambiar su estilo y parece que no puedo funcionar:

class Pill extends React.Component {

  render() {

    return (
      <button className="pill {this.props.styleName}">{this.props.children}</button>
    );
  }

}

<Pill styleName="skill">Business</Pill>

Estoy tratando de cambiar el estilo de la píldora pasando el nombre de la clase que tiene el estilo respectivo. Soy nuevo en React, así que tal vez no esté haciendo esto de la manera correcta. Gracias

hilarante
fuente

Respuestas:

134

En React, cuando desee pasar una expresión interpretada, debe abrir un par de llaves. Tratar:

render () {
  return (
    <button className={`pill ${ this.props.styleName }`}>
      {this.props.children}
    </button>
  );
}

Usando el paquete npm classnames

import classnames from 'classnames';

render() {
  return (
    <button className={classnames('pill', this.props.styleName)}>
      {this.props.children}
    </button>
  );
}
gcedo
fuente
3
¿Por qué es mejor: rendimiento? legibilidad? otros ? Las cadenas literales (su primer ejemplo) son parte de ES6, por lo que es un estándar. Hace menos código y evita una importación. Me siento mejor, pero la otra solución puede tener argumentos.
Mose
2
En el ejemplo anterior tiene toda la razón, es mejor usar cadenas ES6. Yo diría que los nombres de clases son mejores en términos de legibilidad y DRY cuando tienes que lidiar con condicionales, como en el archivo readme de nombres de clases muestra github.com/JedWatson/classnames#usage-with-reactjs .
gcedo
{} Llaves, [] corchetes, () paréntesis: no es necesario que diga "llaves" porque las llaves son curvas por definición.
Rex the Strange
25

Solo como referencia, para componentes sin estado:

// ParentComponent.js
import React from 'react';
import { ChildComponent } from '../child/ChildComponent';

export const ParentComponent = () =>
  <div className="parent-component">
    <ChildComponent className="parent-component__child">
      ...
    </ChildComponent>
  </div>

// ChildComponent.js
import React from 'react';

export const ChildComponent = ({ className, children }) =>
  <div className={`some-css-className ${className}`}>
    {children}
  </div>

Rendirá:

<div class="parent-component">
  <div class="some-css-className parent-component__child">
    ...
  </div>
</div>
Mahdi
fuente
¿No debería agregar la propiedad className a un componente React pasar ese className al primer elemento contenedor en lugar de pasarlo como una propiedad de nombre?
theSereneRebel
1
@theSereneRebel No, no es así. Vea un ejemplo aquí: codesandbox.io/s/clever-knuth-enyju
Mahdi
@theSereneRebel Si eso es bueno o no, es un tema diferente.
Mahdi
18

pill ${this.props.styleName} obtendrá "píldora indefinida" cuando no establezca los accesorios

yo prefiero

className={ "pill " + ( this.props.styleName || "") }

o

className={ "pill " + ( this.props.styleName ? this.props.styleName : "") }
Salarios
fuente
7

Para cualquier persona interesada, me encontré con el mismo problema al usar módulos CSS y reaccionar módulos CSS .

La mayoría de los componentes tienen un estilo de módulo CSS asociado y, en este ejemplo, mi botón tiene su propio archivo CSS, al igual que el componente principal Promo . Pero quiero pasar algunos estilos adicionales a Button desde Promo

Entonces, el stylebotón capaz se ve así:

Button.js

import React, { Component } from 'react'
import CSSModules from 'react-css-modules'
import styles from './Button.css'

class Button extends Component {

  render() {

    let button = null,
        className = ''

    if(this.props.className !== undefined){
        className = this.props.className
    }

    button = (
      <button className={className} styleName='button'>
        {this.props.children}
      </button>
    )

    return (
        button
    );
  }
};

export default CSSModules(Button, styles, {allowMultiple: true} )

En el componente Botón anterior, los estilos Button.css manejan los estilos de botón comunes. En este ejemplo solo una .buttonclase

Luego, en mi componente donde quiero usar el botón , y también quiero modificar cosas como la posición del botón, puedo establecer estilos adicionales Promo.cssy pasarlos como el classNameaccesorio. En este ejemplo nuevamente llamado .buttonclass. Podría haberlo llamado cualquier cosa, por ejemplo promoButton.

Por supuesto, con los módulos css, esta clase será .Promo__button___2MVMDmientras que el botón uno será algo como.Button__button___3972N

Promo.js

import React, { Component } from 'react';
import CSSModules from 'react-css-modules';
import styles from './Promo.css';

import Button from './Button/Button'

class Promo extends Component {

  render() {

    return (
        <div styleName='promo' >
          <h1>Testing the button</h1>
          <Button className={styles.button} >
            <span>Hello button</span>
          </Button>
        </div>
      </Block>
    );
  }
};

export default CSSModules(Promo, styles, {allowMultiple: true} );
svnm
fuente
Actualización de 2018: el uso de propTypes y defaultProps para manejar los casos en los que una propiedad puede existir o no es más limpio y preferido.
BrianHVB
6

Como han dicho otros, use una expresión interpretada con llaves.

Pero no olvide establecer un valor predeterminado.
Otros han sugerido usar una declaración OR para establecer una cadena vacía si undefined.

Pero sería aún mejor declarar tus Props.

Ejemplo completo:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Pill extends Component {

  render() {

    return (
      <button className={`pill ${ this.props.className }`}>{this.props.children}</button>
    );
  }

}

Pill.propTypes = {
  className: PropTypes.string,
};

Pill.defaultProps = {
  className: '',
};
Jamietelin
fuente
4

Puede lograr esto "interpolando" el className pasado del componente principal al componente secundario utilizando this.props.className. Ejemplo a continuación:

export default class ParentComponent extends React.Component {
  render(){
    return <ChildComponent className="your-modifier-class" />
  }
}

export default class ChildComponent extends React.Component {
  render(){
    return <div className={"original-class " + this.props.className}></div>
  }
}
Stafie Anatolie
fuente
1

Con React 16.6.3 y @Material UI 3.5.1, estoy usando matrices en className como className={[classes.tableCell, classes.capitalize]}

Intente algo como lo siguiente en su caso.

class Pill extends React.Component {
    render() {
        return (
           <button className={['pill', this.props.styleName]}>{this.props.children}</button>
        );
    }
}
Devakhim
fuente
0

Con el soporte de React para la interpolación de cadenas, puede hacer lo siguiente:

class Pill extends React.Component {
    render() {
       return (
          <button className={`pill ${this.props.styleName}`}>{this.props.children}</button>
       );
    }
}

Tom Goldenberg
fuente
0

En Typecript, debe establecer tipos de HTMLAttributesy React.FunctionComponent.

En la mayoría de los casos, necesitará extenderlo a otra interfaz o tipo.

const List: React.FunctionComponent<ListProps &
  React.HTMLAttributes<HTMLDivElement>> = (
  props: ListProps & React.HTMLAttributes<HTMLDivElement>
) => {
  return (
    <div className={props.className}>
      <img className="mr-3" src={props.icon} alt="" />
      {props.context}
    </div>
  );
};

interface ListProps {
  context: string;
  icon: string;
}
Objetivos y juegos
fuente