Cómo agregar múltiples clases a un componente ReactJS

346

Soy nuevo en ReactJS y JSX y tengo un pequeño problema con el código a continuación.

Estoy tratando de agregar varias clases al classNameatributo en cada una li:

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

Mi componente Reaccionar es:

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"));
Héctor
fuente
Encontré una respuesta breve aquí stackoverflow.com/a/36209517/4125588 , solo use JavaScript para unirme a estas clases, estáticas o dinámicas, con el operador '+', recuerde insertar '' antes de las clases, excepto la primera, como la real La clase en HTML debe ser como 'ab c', también espacio entre ellos.
Fadeoc Khaos
Posible duplicado de Pasar en nombres de clase para reaccionar componentes
dashdashzako
1
¿Por qué no classNames={{foo: true, bar: true, baz: false}}y classNames={["foo", "bar"]}solo trabajar ?
Peter V. Mørch

Respuestas:

221

Uso los nombres de clase cuando hay una buena cantidad de lógica requerida para decidir las clases que (no) usarán. Un ejemplo demasiado simple :

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

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

Dicho esto, si no desea incluir una dependencia, hay mejores respuestas a continuación.

Jack
fuente
188
Es una lástima que haya tenido que traer una biblioteca de nombres de clase solo para agregar dos clases a un elemento :(
user959690
44
@ user959690 Este es un ejemplo. Esta biblioteca es muy agradable cuando haces mucho estas cosas y tienes una lógica compleja sobre cuándo las clases deben aplicarse o no. Si está haciendo algo simple, entonces solo use plantillas, pero cada caso es diferente y el lector debe elegir la herramienta adecuada para su trabajo.
Jack
77
@ user959690 Vale la pena señalar que ahora NPM lo instala cuando usa Webpack , para import classNames from 'classnames'luego usarlo en un componente className={classNames(classes.myFirstClass, classes.mySecondClass)} .
Hooligancat
55
No es necesario usar una biblioteca externa, vea mi respuesta a continuación.
Huw Davies
1
La biblioteca tiene otras ventajas: 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

Yo uso ES6 plantillas literales . Por ejemplo:

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

Y luego solo renderízalo:

<input className={classes} />

Versión de una línea:

<input className={`form-control round-lg ${this.state.valid ? '' : 'error'}`} />
Damjan Pavlica
fuente
157
También:<input className={`class1 ${class2}`}>
Cody Moniz
3
@unyo Por favor, publique su comentario como respuesta para que pueda votarlo. Se lo merece mucho. He estado buscando durante 1 hora algo tan fácil como esto, y ahora encuentro esto como un comentario. Gracias.
Souvik Ghosh
Esto da como resultado <input class=" form-control input-lg round-lg" />. Tenga en cuenta el espacio extra al principio. Esto es válido, pero feo. Incluso reaccionar FAQ recomienda otra forma o usar el paquete de nombres de
Desnudo
No puedo entender por qué importarías una biblioteca (como en la respuesta aceptada) para configurar algunas clases que se pueden configurar usando Vanilla JavaScript, que de todos modos es una solución más eficiente, limpia y legible.
Marcus Parsons
2
Esta es la respuesta correcta. Usar una dependencia para esto como se sugiere en la respuesta "correcta" es excesivo.
TheDarkIn1978
171

Solo usa JavaScript.

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

Si desea agregar claves y valores basados ​​en clases en un objeto, puede usar lo siguiente:

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

O incluso más simple:

const isEnabled = true;
const isChecked = false;

<li className={[isEnabled && 'enabled', isChecked && 'checked']
  .filter(e => !!e)
  .join(' ')
} />
// Output:
// <li className={'enabled'} />
0xcaff
fuente
Aquí está la línea que funcionó para mí:className={['terra-Table', medOrder.resource.status]}
Doug Wilhelm
1
@DougWilhelm No creo que eso funcione. Implícitamente llama a ToString y crea una lista de clases separadas por comas. github.com/facebook/react/issues/3138
0xcaff
66
Buena idea de usar className={[listOfClasses].join(' ')}, está funcionando para mí, gracias!
Ala Eddine JEBALI
98

Concat

No es necesario ser elegante. Estoy usando módulos CSS y es fácil.

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

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

Esto resultará en:

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

En otras palabras, ambos estilos

Condicionales

Sería fácil usar la misma idea con if's

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

<div className={class1 + ' ' + style.style2} />
Jamie Hutber
fuente
1
Esto funcionó para mí, junto con los nombres '-', es decir: <nav className = {styles.navbar + "" + styles ['navbar-default']}>
Flinkman
LOL, me rompo la cabeza y la respuesta es simple concat: D. Por cierto, esto también funciona con CSS Loader Module
GusDeCooL
El problema con eso es que no puede tener clases opcionales (si no están definidas, entonces no se agregarán), por lo que depende de dónde esté seguro de que su clase no es nula (no opcional). En caso de ser opcional, no hay nada mejor que un ayudante como clases (). podemos usar un ternario con plantillas como ese className={control deslizante $ {className? `$ {className} : ''}}` `. Pero es mucho [nota: 'something' + undefined = 'algo subfinado'. Js conversión dinámica.
Mohamed Allal
Claro que puedes, solo declara una variable arriba y
úsala
42

Esto se puede lograr con los literales de plantilla ES6:

<input className={`class1 ${class2}`}>
Cody Moniz
fuente
1
esto casi funcionó para mí, solo tuve que interpolar la clase 1 también y no más errores, así que se ve así <input className={`${class1} ${class2}`}>
Kingston Fortune
35

Puede crear un elemento con varios nombres de clase como este:

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

Naturalmente, puede usar una cadena que contenga los nombres de clase y manipular esta cadena para actualizar los nombres de clase del elemento.

var myClassNammes = 'class1 class2 class3';
...
<li className={myClassNames}>foo</li>
nightlyop
fuente
1
¿Probaste esto? Lo hice :)
cuervo
Sí, lo hice. En realidad, lo uso con bastante frecuencia, pero acabo de ver y corregir un error tipográfico. Por supuesto, la cadena que contiene los nombres de clase en la primera línea debe hacerse usando en "lugar de '. Lo siento por eso.
nightlyop
20

Así es como puedes hacer eso con ES6:

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

Puede enumerar múltiples clases y condiciones y también puede incluir clases estáticas. No es necesario agregar una biblioteca adicional.

Buena suerte ;)

Hristo Eftimov
fuente
2
Esto da como resultado HTML muy feo, considerando todo el espacio en blanco adicional.
Desnudo
2
No es necesario escribir así. Este es solo un ejemplo que explica mejor la solución. Y siempre en producción tienes la versión minificada :)
Hristo Eftimov
18

Vanilla JS

No necesita bibliotecas externas: solo use cadenas de plantilla ES6 :

<i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>
Huw Davies
fuente
Vanilla JS NO ES ES6. Pero me gusta tu ejemplo.
RyanNerd
8
@RyanNerd ¿Quieres decir "ES6 no es vanilla JS"? De todos modos, lo es, porque vanilla js significa javascript sin ningún marco. ES6 es una versión más nueva de javascript. - stackoverflow.com/a/20435685/5111113
Huw Davies
No es una respuesta incorrecta, pero podría mejorarse mucho. Por ejemplo, todos los demás agregaron ejemplos sobre estados.
JGallardo
10

Tal vez los nombres de clase pueden ayudarte.

var classNames = require('classnames');
classNames('foo', {'xx-test': true, bar: false}, {'ox-test': false}); // => 'foo xx-test'
xsong
fuente
1
¿Puedes hacer que este ejemplo sea más útil?
JGallardo
9

No creo que necesitemos usar un paquete externo para solo agregar varias clases.

Yo personalmente uso

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

o

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

el segundo en caso de que necesite agregar o eliminar clases condicionalmente.

Pasham Akhil Kumar Reddy
fuente
1
esto agregará solo una clase de cualquier manera.
TrickOrTreat
6

Solo agregando, podemos filtrar cadenas vacías.

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

Puede crear un elemento con múltiples nombres de clase como este, lo intenté en ambos sentidos, funciona bien ...

Si importa cualquier CSS, puede seguir este camino: Modo 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>
    );
  }
}

camino 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 aplica css como interno:

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
fuente
6

Podrías hacer lo siguiente:

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

Una solución corta y simple, espero que esto ayude.

Alberto Perez
fuente
4

Tarde a la fiesta, pero ¿por qué usar un tercero para un problema tan simple?

Podrías hacerlo como mencionó @Huw Davies: la mejor manera

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

Ambos son buenos. Pero escribir puede volverse complejo para una aplicación grande. Para hacerlo óptimo, hago lo mismo arriba pero lo pongo en una clase auxiliar

El uso de mi función de ayuda a continuación, me permite mantener la lógica separada para futuras ediciones, y también me brinda múltiples formas de agregar las clases

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

o

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

Esta es mi función de ayuda a continuación. Lo puse en un helper.js donde guardo todos mis métodos comunes. Al ser una función tan simple, evité usar un tercero para mantener el control

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

Puede usar matrices y luego unirlas usando el espacio.

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

Esto resultará en:

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

Sé que esta es una respuesta tardía, pero espero que esto ayude a alguien.

Tenga en cuenta que ha definido las siguientes clases en un archivo css ' primario ', ' font-i ', ' font-xl '

  • El primer paso sería importar el archivo CSS.
  • Entonces

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

haría el truco!

Para más información: https://www.youtube.com/watch?v=j5P9FHiBVNo&list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3&index=20

Achintha Isuru
fuente
3

para más clases agregando

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

Usando el ejemplo de Facebook TodoTextInput.js

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

Reemplazar los nombres de clase con código simple vanilla js se verá así:

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
fuente
2

Si no tiene ganas de importar otro módulo, esta función funciona como el classNamesmódulo.

function classNames(rules) {
    var classes = ''

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

    return classes
} 

Puedes usarlo así:

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

    return (
        <SomeComponent style={classes} />
    )
}
Seth
fuente
¿Por qué usar cierres si puedes hacer lo mismo con map o reduce? function classNames(rules) { return Object.entries(rules) .reduce( (arr, [cls, flag]) => { if (flag) arr.push(cls); return arr }, [] ).join(" ") }
Евгений Савичев
1

Eso es lo que hago:

Componente:

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

Componente de llamada:

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

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

Entonces, en su ejemplo, lo siguiente sería similar.

<li key={index} className={[activeClass, data.class, "main-class"]}></li>
Devakhim
fuente
Esto es lo que estaba haciendo (aunque no MUI) y no funciona, solo aplica la primera clase, sin advertencia ni queja.
Juan Lanus
1

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

importar classNames desde 'nombres de clase';

  1. Puede usar múltiples clases usando comas separadas:

    <li className={classNames(classes.tableCellLabel, classes.tableCell)}>Total</li>
  2. Puede usar múltiples clases usando comas separadas con condición:

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

El uso de array como accesorios para classNames también funcionará, pero da una advertencia, por ejemplo

className={[classes.tableCellLabel, classes.tableCell]}
Vikramjit Singh
fuente
Duplicado de otra respuesta existente .
Jack Bashford
0

Yo uso el paquete 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
})} />

Puede agregar clases en cualquier formato (matriz, objeto, argumento). Todos los valores verdaderos de matrices o argumentos más claves en objetos que equivalen atrue fusionarse.

por ejemplo:

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
fuente
0

I bind classNamesal módulo css importado al componente.

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

classnames da la capacidad de declarar className un elemento React de forma declarativa.

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
fuente
0

Usualmente lo uso así: (en tu caso)

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

Cuando se trata de JSX y (por lo general) tenemos algo de json ... de lo que lo bucle ... componente . map , más algunos condicionales para verificar si la propiedad json existe para representar el nombre de la clase dependiendo del valor de la propiedad de JSON. En el siguiente ejemplo, component_color y component_dark_shade son propiedades de component.map ()

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

Salida: <div class="component no-color light" .... O: <div class="component blue dark" ....dependiendo de los valores del mapa ...

StefaDesign
fuente
0

Cuando tengo muchas clases diferentes, he encontrado que lo siguiente es útil.

El filtro elimina cualquiera de los nullvalores y la unión coloca todos los valores restantes en una cadena separada por espacios.

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

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