Comment ajouter plusieurs classes à un composant ReactJS

346

Je suis nouveau sur ReactJS et JSX et j'ai un petit problème avec le code ci-dessous.

J'essaie d'ajouter plusieurs classes à l' classNameattribut sur chacune li:

<li key={index} className={activeClass, data.class, "main-class"}></li>

Mon composant React est:

var AccountMainMenu = React.createClass({
  getInitialState: function() {
    return { focused: 0 };
  },

  clicked: function(index) {
    this.setState({ focused: index });
  },

  render: function() {
    var self = this;
    var accountMenuData = [
      {
        name: "My Account",
        icon: "icon-account"
      },
      {
        name: "Messages",
        icon: "icon-message"
      },
      {
        name: "Settings",
        icon: "icon-settings"
      }
    /*{
        name:"Help &amp; Support &nbsp; <span class='font-awesome icon-support'></span>(888) 664.6261",
        listClass:"no-mobile last help-support last"
      }*/
    ];

    return (
      <div className="acc-header-wrapper clearfix">
        <ul className="acc-btns-container">
          {accountMenuData.map(function(data, index) {
            var activeClass = "";

            if (self.state.focused == index) {
              activeClass = "active";
            }

            return (
              <li
                key={index}
                className={activeClass}
                onClick={self.clicked.bind(self, index)}
              >
                <a href="#" className={data.icon}>
                  {data.name}
                </a>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
});

ReactDOM.render(<AccountMainMenu />, document.getElementById("app-container"));
Hector
la source
J'ai trouvé une réponse brève ici stackoverflow.com/a/36209517/4125588 , il suffit d'utiliser JavaScript pour rejoindre ces classes, statiques ou dynamiques, avec l'opérateur '+', n'oubliez pas d'insérer '' avant les classes sauf la première, comme le vrai La classe en HTML devrait être comme «ab c», également un espace entre eux.
Fadeoc Khaos
Duplication possible des noms de classe Passing in pour réagir aux composants
dashdashzako
1
Pourquoi ne pas travaillerclassNames={{foo: true, bar: true, baz: false}} et classNames={["foo", "bar"]}simplement ?
Peter V. Mørch

Réponses:

221

J'utilise des noms de classe quand il y a une bonne quantité de logique requise pour décider des classes à (ne pas) utiliser. Un exemple trop simple :

...
    var liClasses = classNames({
      'main-class': true,
      'activeClass': self.state.focused === index
    });

    return (<li className={liClasses}>{data.name}</li>);
...

Cela dit, si vous ne voulez pas inclure de dépendance, il y a de meilleures réponses ci-dessous.

Jack
la source
189
C'est dommage que vous ayez dû apporter une bibliothèque de noms de classes juste pour ajouter deux classes à un élément :(
user959690
4
@ user959690 Ceci est un exemple. Cette bibliothèque est très agréable lorsque vous faites beaucoup de choses et que vous avez une logique complexe sur le moment où les classes doivent être appliquées ou non. Si vous faites quelque chose de simple, utilisez simplement des modèles, mais chaque cas est différent et le lecteur doit choisir le bon outil pour son travail.
Jack
7
@ user959690 Il convient de noter qu'il est désormais installé par NPM lors de l'utilisation de Webpack , donc import classNames from 'classnames'à utiliser dans un composant className={classNames(classes.myFirstClass, classes.mySecondClass)} .
Hooligancat
5
Pas besoin d'utiliser une bibliothèque externe, voir ma réponse ci-dessous.
Huw Davies
1
La bibliothèque a d'autres avantages: var btnClass = classNames({ btn: true, 'btn-pressed': this.state.isPressed, 'btn-over': !this.state.isPressed && this.state.isHovered }); return <button className={btnClass}>{this.props.label}</button>;
AmitJS94
395

J'utilise des ES6 modèles de littéraux . Par exemple:

const error = this.state.valid ? '' : 'error'
const classes = `form-control round-lg ${error}`

Et puis il suffit de le rendre:

<input className={classes} />

Version à une ligne:

<input className={`form-control round-lg ${this.state.valid ? '' : 'error'}`} />
Damjan Pavlica
la source
157
Aussi:<input className={`class1 ${class2}`}>
Cody Moniz
3
@unyo Veuillez poster votre commentaire comme réponse afin que je puisse le voter. Il le mérite tellement. Je cherche depuis 1 heure quelque chose d'aussi simple que cela, et maintenant je trouve cela enterré en tant que commentaire. Je vous remercie.
Souvik Ghosh
Cela se traduit par <input class=" form-control input-lg round-lg" />. Notez l'espace supplémentaire au début. C'est valide, mais moche. Même React FAQ recommande une autre méthode ou l'utilisation du package classnames
Nakedible
Je ne comprends pas pourquoi vous importeriez une bibliothèque (comme dans la réponse acceptée) pour simplement définir certaines classes qui peuvent être définies à l'aide de Vanilla JavaScript, qui est de toute façon une solution plus efficace, plus propre et plus lisible.
Marcus Parsons
2
Ceci est la bonne réponse. Utiliser une dépendance pour cela comme suggéré dans la réponse "correcte" est exagéré.
TheDarkIn1978
171

Utilisez simplement JavaScript.

<li className={[activeClass, data.klass, "main-class"].join(' ')} />

Si vous souhaitez ajouter des clés et des valeurs basées sur des classes dans un objet, vous pouvez utiliser les éléments suivants:

function classNames(classes) {
  return Object.entries(classes)
    .filter(([key, value]) => value)
    .map(([key, value]) => key)
    .join(' ');
}

const classes = {
  'maybeClass': true,
  'otherClass': true,
  'probablyNotClass': false,
};

const myClassNames = classNames(classes);
// Output: "maybeClass otherClass"

<li className={myClassNames} />

Ou encore plus simple:

const isEnabled = true;
const isChecked = false;

<li className={[isEnabled && 'enabled', isChecked && 'checked']
  .filter(e => !!e)
  .join(' ')
} />
// Output:
// <li className={'enabled'} />
0xcaff
la source
Voici la ligne qui a fonctionné pour moi:className={['terra-Table', medOrder.resource.status]}
Doug Wilhelm
1
@DougWilhelm Je ne pense pas que cela fonctionne. Il appelle implicitement toString et crée une liste de classes séparées par des virgules. github.com/facebook/react/issues/3138
0xcaff
6
Bonne idée d'utiliser className={[listOfClasses].join(' ')}ça marche pour moi merci!
Ala Eddine JEBALI
98

Concat

Pas besoin d'être chic j'utilise des modules CSS et c'est facile

import style from '/css/style.css';

<div className={style.style1+ ' ' + style.style2} />

Cela se traduira par:

<div class="src-client-css-pages-style1-selectionItem src-client-css-pages-style2">

En d'autres termes, les deux styles

Conditionnels

Il serait facile d'utiliser la même idée avec if

const class1 = doIHaveSomething ? style.style1 : 'backupClass';

<div className={class1 + ' ' + style.style2} />
Jamie Hutber
la source
1
Cela a fonctionné pour moi, avec les noms '-', c'est-à-dire: <nav className = {styles.navbar + "" + styles ['navbar-default']}>>
Flinkman
LOL, je me casse la tête et la réponse est simple: D. Btw ce travail aussi avec CSS Loader Module
GusDeCooL
Le problème avec cela est que vous ne pouvez pas avoir de classes optionnelles (si elles ne sont pas définies, elles ne seront pas ajoutées), cela dépend donc de la certitude que votre classe n'est pas nulle (non optionnelle). En cas de facultatif, il n'y a pas mieux qu'un assistant comme classes (). nous pouvons utiliser un ternaire avec des modèles comme ce className={curseur $ {className? `$ {className} : ''}}` `. Mais c'est beaucoup. [note: 'quelque chose' + undefined = 'quelque chose de sous-défini'. Conversion dynamique Js.
Mohamed Allal
Bien sûr, vous pouvez simplement déclarer une variable ci-dessus et l'utiliser conditionnellement :)
Jamie Hutber
42

Cela peut être réalisé avec les littéraux de modèle ES6:

<input className={`class1 ${class2}`}>
Cody Moniz
la source
1
cela a presque fonctionné pour moi J'ai juste eu à interpoler la classe 1 aussi et plus d'erreurs, donc ça ressemble à ça <input className={`${class1} ${class2}`}>
Kingston Fortune
35

Vous pouvez créer un élément avec plusieurs noms de classe comme celui-ci:

<li className="class1 class2 class3">foo</li>

Naturellement, vous pouvez utiliser une chaîne contenant les noms de classe et manipuler cette chaîne pour mettre à jour les noms de classe de l'élément.

var myClassNammes = 'class1 class2 class3';
...
<li className={myClassNames}>foo</li>
soirée
la source
1
Avez-vous testé cela? Je l'ai fait :)
corbeau
Oui je l'ai fait. En fait, je l'utilise assez souvent, mais je viens de voir et de corriger une faute de frappe. Bien sûr, la chaîne contenant les noms de classe dans la première ligne doit être créée à la "place de '. Désolé pour ça.
soir
20

Voici comment vous pouvez le faire avec ES6:

className = {`
      text-right
      ${itemId === activeItemId ? 'active' : ''}
      ${anotherProperty === true ? 'class1' : 'class2'}
`}

Vous pouvez répertorier plusieurs classes et conditions et vous pouvez également inclure des classes statiques. Il n'est pas nécessaire d'ajouter une bibliothèque supplémentaire.

Bonne chance ;)

Hristo Eftimov
la source
2
Cela se traduit par un code HTML très laid, compte tenu de tous les espaces supplémentaires.
Nakedible
2
Il n'est pas nécessaire d'écrire comme ça. Ceci est juste un exemple qui explique mieux la solution. Et toujours en production vous avez la version minifiée :)
Hristo Eftimov
18

Vanilla JS

Pas besoin de bibliothèques externes - utilisez simplement les chaînes de modèle ES6 :

<i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>
Huw Davies
la source
Vanilla JS n'est PAS ES6. Mais j'aime bien votre exemple.
RyanNerd
8
@RyanNerd Vous voulez dire "ES6 n'est pas vanille JS"? Quoi qu'il en soit, car vanilla js signifie javascript sans aucun framework. ES6 est une nouvelle version de javascript. - stackoverflow.com/a/20435685/5111113
Huw Davies
Pas une mauvaise réponse mais pourrait être beaucoup améliorée. Par exemple, tout le monde a ajouté des exemples sur les États.
JGallardo
10

Peut-être que les noms de classe peuvent vous aider.

var classNames = require('classnames');
classNames('foo', {'xx-test': true, bar: false}, {'ox-test': false}); // => 'foo xx-test'
xsong
la source
1
Pouvez-vous rendre cet exemple plus utilisable.
JGallardo
9

Je ne pense pas que nous ayons besoin d'utiliser un package externe pour simplement ajouter plusieurs classes.

J'utilise personnellement

<li className={`li active`}>Stacy</li>

ou

<li className={`li ${this.state.isActive ? 'active' : ''}`}>Stacy<li>

le second au cas où vous auriez besoin d'ajouter ou de supprimer des classes de façon conditionnelle.

Pasham Akhil Kumar Reddy
la source
1
cela n'ajoutera qu'une seule classe dans les deux cas.
TrickOrTreat
6

En ajoutant simplement, nous pouvons filtrer les chaînes vides.

className={[
    'read-more-box',
    this.props.className,
    this.state.isExpanded ? 'open' : 'close',
].filter(x => !!x).join(' ')}
Himanshu Jariyal
la source
6

Vous pouvez créer un élément avec plusieurs noms de classe comme celui-ci, j'ai essayé ces deux façons, son bon fonctionnement ...

Si vous importez un fichier CSS, vous pouvez suivre cette procédure: Méthode 1:

import React, { Component, PropTypes } from 'react';
import csjs from 'csjs';
import styles from './styles';
import insertCss from 'insert-css';
import classNames from 'classnames';
insertCss(csjs.getCss(styles));
export default class Foo extends Component {
  render() {
    return (
      <div className={[styles.class1, styles.class2].join(' ')}>
        { 'text' }
      </div>
    );
  }
}

voie 2:

import React, { Component, PropTypes } from 'react';
import csjs from 'csjs';
import styles from './styles';
import insertCss from 'insert-css';
import classNames from 'classnames';
insertCss(csjs.getCss(styles));
export default class Foo extends Component {
  render() {
    return (
      <div className={styles.class1 + ' ' + styles.class2}>
        { 'text' }
      </div>
    );
  }
}

**

Si vous appliquez css en interne:

const myStyle = {
  color: "#fff"
};

// React Element using Jsx
const myReactElement = (
  <h1 style={myStyle} className="myClassName myClassName1">
    Hello World!
  </h1>
);

ReactDOM.render(myReactElement, document.getElementById("app"));
.myClassName {
  background-color: #333;
  padding: 10px;
}
.myClassName1{
  border: 2px solid #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
<div id="app">
  
</div>

arvinda kumar
la source
6

Vous pouvez effectuer les opérations suivantes:

<li key={index} className={`${activeClass} ${data.class} main-class`}></li>

Une solution courte et simple, j'espère que cela vous aidera.

Alberto Perez
la source
5

Cela peut être fait avec https://www.npmjs.com/package/clsx :

https://www.npmjs.com/package/clsx

Installez-le d'abord:

npm install --save clsx

Importez-le ensuite dans votre fichier de composant:

import clsx from  'clsx';

Utilisez ensuite la fonction importée dans votre composant:

<div className={ clsx(classes.class1, classes.class2)}>
Yanga
la source
4

Tard dans la fête, mais pourquoi utiliser un tiers pour un problème aussi simple?

Vous pouvez soit le faire comme l'a mentionné @Huw Davies - la meilleure façon

1. <i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>
2. <i className={[styles['foo-bar-baz'], 'fa fa-user', 'fa-2x'].join(' ')}

Les deux sont bons. Mais l'écriture peut devenir complexe pour une grande application. Pour le rendre optimal, je fais les mêmes choses ci-dessus mais je le mets dans une classe d'aide

L'utilisation de ma fonction d'aide ci-dessous, me permet de garder la logique séparée pour les modifications futures, et me donne également plusieurs façons d'ajouter les classes

classNames(styles['foo-bar-baz], 'fa fa-user', 'fa-2x')

ou

classNames([styles['foo-bar-baz], 'fa fa-user', 'fa-2x'])

Ceci est ma fonction d'aide ci-dessous. Je l'ai mis dans un helper.js où je garde toutes mes méthodes courantes. Étant une fonction aussi simple, j'ai évité d'utiliser une tierce partie pour garder le contrôle

export function classNames (classes) {
    if(classes && classes.constructor === Array) {
        return classes.join(' ')
    } else if(arguments[0] !== undefined) {
        return [...arguments].join(' ')
    }
    return ''
}
Elton Jain
la source
3

Vous pouvez utiliser des tableaux puis les joindre en utilisant l'espace.

<li key={index} className={[activeClass, data.class, "main-class"].join(' ')}></li>

Cela se traduira par:

<li key={index} class="activeClass data.class main-class"></li>
Vinay Jariya
la source
3

Je sais que c'est une réponse tardive, mais j'espère que cela aidera quelqu'un.

Considérez que vous avez défini les classes suivantes dans un fichier css « primaire », « font-i », « font-xl »

  • La première étape serait d'importer le fichier CSS.
  • alors

<h3 class = {` ${'primary'} ${'font-i'} font-xl`}> HELLO WORLD </h3>

ferait l'affaire!

Pour plus d'informations: https://www.youtube.com/watch?v=j5P9FHiBVNo&list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3&index=20

Achintha Isuru
la source
3

pour plus de classes en ajoutant

... className={`${classes.hello} ${classes.hello1}`...
Rama Krishna
la source
2

Utilisation de l'exemple TodoTextInput.js de Facebook

render() {
    return (
      <input className={
        classnames({
          edit: this.props.editing,
          'new-todo': this.props.newTodo
        })}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  } 

remplacer les noms de classe par du code js ordinaire vanilla ressemblera à ceci:

render() {
    return (
      <input
        className={`
          ${this.props.editing ? 'edit' : ''} ${this.props.newTodo ? 'new-todo' : ''}
        `}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  }
Vlad Bezden
la source
2

Si vous n'avez pas envie d'importer un autre module, cette fonction fonctionne comme le classNamesmodule.

function classNames(rules) {
    var classes = ''

    Object.keys(rules).forEach(item => {    
        if (rules[item])
            classes += (classes.length ? ' ' : '') + item
    })

    return classes
} 

Vous pouvez l'utiliser comme ceci:

render() {
    var classes = classNames({
        'storeInfoDiv': true,  
        'hover': this.state.isHovered == this.props.store.store_id
    })   

    return (
        <SomeComponent style={classes} />
    )
}
Seth
la source
Pourquoi utiliser des fermetures si vous pouvez faire de même avec la carte ou réduire? function classNames(rules) { return Object.entries(rules) .reduce( (arr, [cls, flag]) => { if (flag) arr.push(cls); return arr }, [] ).join(" ") }
Евгений Савичев
1

C'est ce que je fais:

Composant:

const Button = ({ className }) => (
  <div className={ className }> </div>
);

Composant appelant:

<Button className = 'hashButton free anotherClass' />
RegarBoy
la source
1

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

Donc, dans votre exemple, ce qui suit serait similaire.

<li key={index} className={[activeClass, data.class, "main-class"]}></li>
Devakhim
la source
C'est ce que je faisais (bien qu'il n'y ait pas de MUI) et ne fonctionne pas, applique uniquement la première classe - pas d'avertissement ni de plainte.
Juan Lanus
1

Utilisez https://www.npmjs.com/package/classnames

importer classNames à partir de 'classnames';

  1. Peut utiliser plusieurs classes en utilisant des comas séparés:

    <li className={classNames(classes.tableCellLabel, classes.tableCell)}>Total</li>
  2. Peut utiliser plusieurs classes en utilisant des comas séparés avec condition:

    <li className={classNames(classes.buttonArea, !nodes.length && classes.buttonAreaHidden)}>Hello World</li> 

L'utilisation de tableaux comme accessoires pour classNames fonctionnera également, mais donne un avertissement, par exemple

className={[classes.tableCellLabel, classes.tableCell]}
Vikramjit Singh
la source
Duplication d' une autre réponse existante .
Jack Bashford
0

J'utilise le package rc-classnames .

// ES6
import c from 'rc-classnames';

// CommonJS
var c = require('rc-classnames');

<button className={c('button', {
  'button--disabled': isDisabled,
  'button--no-radius': !hasRadius
})} />

Vous pouvez ajouter des classes dans n'importe quel format (tableau, objet, argument). Toutes les valeurs véridiques des tableaux ou des arguments et des clés dans les objets qui sont égales pour trueêtre fusionnées ensemble.

par exemple:

ReactClassNames('a', 'b', 'c') // => "a b c"
ReactClassNames({ 'a': true, 'b': false, c: 'true' }) // => "a c"
ReactClassNames(undefined, null, 'a', 0, 'b') // => "a b"
morajabi
la source
0

Je bind classNamesau module CSS importé dans le composant.

import classNames from 'classnames'; 
import * as styles from './[STYLES PATH];
const cx = classNames.bind(styles); 

classnamesdonne la possibilité de déclarer classNamepour un élément React d'une manière déclarative.

ex:

<div classNames={cx(styles.titleText)}> Lorem </div>

<div classNames={cx('float-left')}> Lorem </div> // global css declared without css modules
<div classNames={cx( (test === 0) ?
             styles.titleText : 
             styles.subTitleText)}>  Lorem </div> // conditionally assign classes

<div classNames={cx(styles.titleText, 'float-left')}> Lorem </div> //combine multiple classes
Rajendra kumar Vankadari
la source
0

Je l'utilise habituellement comme ceci: (dans votre cas)

    <li  key={index} className={
        "component " +
        `${activeClass? activeClass: " not-an-active-class "}` +
        `${data.class? " " + data.class : " no-data-class "}`
   } />

Quand il s'agit de JSX et (généralement) nous avons du json ... que vous bouclez ... composant . map , plus quelques conditions pour vérifier si la propriété json existe pour rendre le nom de la classe en fonction de la valeur de la propriété de JSON. Dans l'exemple ci-dessous, component_color et component_dark_shade sont des propriétés de component.map ()

   <div className={
        "component " +
        `${component_color? component_color: " no-color "}` +
        `${component_dark_shade? " " + component_dark_shade : " light "}`
   }/>

Sortie: <div class="component no-color light" .... Ou: en <div class="component blue dark" ....fonction des valeurs de la carte ...

StefaDesign
la source
0

Lorsque j'ai plusieurs classes différentes, j'ai trouvé les éléments suivants utiles.

Le filtre supprime toutes les nullvaleurs et la jointure place toutes les valeurs restantes dans une chaîne séparée par des espaces.

const buttonClasses = [
    "Button", 
    disabled ? "disabled" : null,
    active ? "active" : null
].filter((class) => class).join(" ")

<button className={buttonClasses} onClick={onClick} disabled={disabled ? disabled : false}>
Michael Murphy
la source