Transmitindo nomes de classes para componentes de reação

92

Estou tentando passar um nome de classe para um componente de reação para alterar seu estilo e não consigo funcionar:

class Pill extends React.Component {

  render() {

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

}

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

Estou tentando mudar o estilo da pílula passando no nome da classe que tem o respectivo estilo. Eu sou novo no React, então talvez eu não esteja fazendo isso da maneira certa. obrigado

hilarl
fonte

Respostas:

130

No React, quando você deseja passar uma expressão interpretada, deve abrir um par de chaves. Experimentar:

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

Usando o pacote classnames npm

import classnames from 'classnames';

render() {
  return (
    <button className={classnames('pill', this.props.styleName)}>
      {this.props.children}
    </button>
  );
}
gcedo
fonte
3
Por que é melhor: desempenho? legibilidade? outras ? Strings literais (seu primeiro exemplo) fazem parte do ES6, então é um padrão. Torna menos código e evita uma importação. Ele se sente melhor para mim, mas a outra solução pode ter argumentos.
Mose,
2
No exemplo acima, você está absolutamente certo, é melhor usar strings ES6. Eu diria que os nomes de classe são melhores em termos de legibilidade e DRY quando você tem que lidar com condicionais, como no readme de nomes de classe mostra github.com/JedWatson/classnames#usage-with-reactjs .
gcedo
{} Chaves, [] colchetes, () Parênteses - você não precisa dizer "colchetes" porque os colchetes são curvas por definição.
Rex the Strange
21

Apenas para referência, para componentes sem 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>

Irá renderizar:

<div class="parent-component">
  <div class="some-css-className parent-component__child">
    ...
  </div>
</div>
Mahdi
fonte
Adicionar className prop a um componente React não deveria passar esse className para o primeiro elemento de contêiner em vez de passá-lo como um nome prop?
theSereneRebel
@theSereneRebel Não, não importa. Veja um exemplo aqui: codesandbox.io/s/clever-knuth-enyju
Mahdi
@theSereneRebel Se isso é bom ou não, é um assunto diferente.
Mahdi
17

pill ${this.props.styleName} obterá "pílula indefinida" quando você não definir os adereços

eu prefiro

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

ou

className={ "pill " + ( this.props.styleName ? this.props.styleName : "") }
salários
fonte
7

Para qualquer pessoa interessada, encontrei o mesmo problema ao usar módulos css e módulos css react .

A maioria dos componentes tem um estilo de módulo css associado e, neste exemplo, meu botão tem seu próprio arquivo css, assim como o componente pai Promo . Mas eu quero passar alguns estilos adicionais para Button from Promo

Portanto, o stylebotão capaz se parece com isto:

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} )

No componente Button acima, os estilos Button.css tratam dos estilos de botão comuns. Neste exemplo, apenas uma .buttonclasse

Então, no meu componente onde desejo usar o Botão e também quero modificar coisas como a posição do botão, posso definir estilos extras Promo.csse passar como o classNamesuporte. Neste exemplo, novamente chamado de .buttonclasse. Eu poderia ter chamado de qualquer coisa, por exemplo promoButton.

Claro que com os módulos css esta classe será, .Promo__button___2MVMDenquanto o botão 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
fonte
Atualização de 2018: usar propTypes e defaultProps para lidar com casos em que uma propriedade pode ou não existir é mais claro e preferencial.
BrianHVB de
6

Como já foi dito, use uma expressão interpretada com chaves.

Mas não se esqueça de definir um padrão.
Outros sugeriram o uso de uma instrução OR para definir uma string vazia if undefined.

Mas seria ainda melhor declarar seus adereços.

Exemplo 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
fonte
4

Você pode fazer isso "interpolando" o className passado do componente pai para o componente filho usando this.props.className. Exemplo abaixo:

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
fonte
1

Com React 16.6.3 e @Material UI 3.5.1, estou usando matrizes em className como className={[classes.tableCell, classes.capitalize]}

Tente algo como o seguinte no seu caso.

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

Com o suporte do React para interpolação de strings, você pode fazer o seguinte:

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

Tom Goldenberg
fonte
0

Em Typescript você precisa definir os tipos de HTMLAttributese React.FunctionComponent.

Na maioria dos casos, você precisará estendê-lo para outra interface ou 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;
}
Ferrugem
fonte