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"));

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


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.


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

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

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

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

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>

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


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

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'

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.


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

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>


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.



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

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>

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


3

para más clases agregando

... className={`${classes.hello} ${classes.hello1}`...

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

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

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

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>

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


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"

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

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


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}>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.