Passer des noms de classes pour réagir aux composants

92

J'essaie de passer un nom de classe à un composant de réaction pour changer son style et je n'arrive pas à fonctionner:

class Pill extends React.Component {

  render() {

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

}

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

J'essaye de changer le style de la pilule en passant le nom de la classe qui a le style respectif. Je suis nouveau sur React, alors peut-être que je ne fais pas cela de la bonne façon. Merci

Hilarl
la source

Réponses:

130

Dans React, lorsque vous souhaitez transmettre une expression interprétée, vous devez ouvrir une paire d'accolades. Essayer:

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

Utilisation du package classnames npm

import classnames from 'classnames';

render() {
  return (
    <button className={classnames('pill', this.props.styleName)}>
      {this.props.children}
    </button>
  );
}
gcedo
la source
3
Pourquoi est-ce mieux: la performance? lisibilité? autres ? Les chaînes littérales (votre premier exemple) font partie de ES6, c'est donc une norme. Cela fait moins de code et évite une importation. Cela me va mieux, mais l'autre solution peut avoir des arguments.
Mose
2
Dans l'exemple ci-dessus, vous avez tout à fait raison, il est préférable d'utiliser des chaînes ES6. Je dirais que les noms de classe sont meilleurs en termes de lisibilité et de DRY lorsque vous devez gérer des conditions, comme dans les noms de classe readme montre github.com/JedWatson/classnames#usage-with-reactjs .
gcedo
{} Accolades, [] Crochets, () Parenthèses - vous n'avez pas besoin de dire "accolades" car les accolades sont bouclées par définition.
Rex the Strange
21

Juste pour la référence, pour les composants sans état:

// 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>

Rendra:

<div class="parent-component">
  <div class="some-css-className parent-component__child">
    ...
  </div>
</div>
Mahdi
la source
L'ajout d'un prop className à un composant React ne devrait-il pas passer ce className au premier élément de conteneur au lieu de le passer en tant que prop de nom?
theSereneRebel
@theSereneRebel Non, ce n'est pas le cas. Voir un exemple ici: codesandbox.io/s/clever-knuth-enyju
Mahdi
@theSereneRebel Que ce soit une bonne chose ou non, c'est un autre sujet.
Mahdi
17

pill ${this.props.styleName} obtiendra "pill undefined" si vous ne définissez pas les accessoires

je préfère

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

ou

className={ "pill " + ( this.props.styleName ? this.props.styleName : "") }
salars
la source
7

Pour toute personne intéressée, j'ai rencontré ce même problème lors de l'utilisation de modules css et de la réaction des modules css .

La plupart des composants ont un style de module css associé, et dans cet exemple, mon Button a son propre fichier css, tout comme le composant parent Promo . Mais je souhaite transmettre des styles supplémentaires à Button de Promo

Donc, le stylebouton capable ressemble à ceci:

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

Dans le composant Button ci-dessus, les styles Button.css gèrent les styles de bouton courants. Dans cet exemple, juste une .buttonclasse

Ensuite, dans mon composant où je veux utiliser le bouton , et je veux également modifier des choses comme la position du bouton, je peux définir des styles supplémentaires Promo.csset passer comme classNameaccessoire. Dans cet exemple encore appelé .buttonclass. J'aurais pu l'appeler n'importe quoi, par exemple promoButton.

Bien sûr, avec les modules css, cette classe sera .Promo__button___2MVMDalors que le bouton sera quelque chose comme.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
la source
Mise à jour 2018: l'utilisation de propTypes et defaultProps pour gérer les cas où une propriété peut exister ou non est plus propre et préférable.
BrianHVB
6

Comme d'autres l'ont indiqué, utilisez une expression interprétée avec des accolades.

Mais n'oubliez pas de définir une valeur par défaut.
D'autres ont suggéré d'utiliser une instruction OR pour définir une chaîne vide if undefined.

Mais ce serait encore mieux de déclarer vos accessoires.

Exemple complet:

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
la source
4

Vous pouvez y parvenir en "interpolant" le nom de classe passé du composant parent au composant enfant à l'aide de this.props.className. Exemple ci-dessous:

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
la source
1

Avec React 16.6.3 et @Material UI 3.5.1, j'utilise des tableaux dans className comme className={[classes.tableCell, classes.capitalize]}

Essayez quelque chose comme ce qui suit dans votre cas.

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

Avec le support de React pour l'interpolation de chaîne, vous pouvez effectuer les opérations suivantes:

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

Tom Goldenberg
la source
0

Dans Typescript, vous devez définir les types de HTMLAttributeset React.FunctionComponent.

Dans la plupart des cas, vous devrez l'étendre à une autre interface ou un autre type.

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;
}
Rouille
la source