Reaccione Js aplicando condicionalmente atributos de clase

334

Quiero mostrar y ocultar condicionalmente este grupo de botones dependiendo de lo que se pasa del componente principal que se ve así:

<TopicNav showBulkActions={this.__hasMultipleSelected} />

....

__hasMultipleSelected: function() {
  return false; //return true or false depending on data
}

....

var TopicNav = React.createClass({
render: function() {
return (
    <div className="row">
        <div className="col-lg-6">
            <div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}">
                <button type="button" className="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                  Bulk Actions <span className="caret"></span>
                </button>
                <ul className="dropdown-menu" role="menu">
                  <li><a href="#">Merge into New Session</a></li>
                  <li><a href="#">Add to Existing Session</a></li>
                  <li className="divider"></li>
                  <li><a href="#">Delete</a></li>
                </ul>
            </div>
        </div>
    </div>
    );
  }
});

Sin embargo, no pasa nada con las {this.props.showBulkActions? 'show': 'oculto'}. ¿Estoy haciendo algo mal aquí?

apexdodge
fuente
También es posible que desee considerar react-bootstrap , ya que esto resume algunas de las cosas de la clase en propiedades de componentes, lo que hace que lo que intenta hacer sea un poco más fácil.
Dancrumb

Respuestas:

591

Las llaves están dentro de la cadena, por lo que se evalúa como cadena. Necesitan estar afuera, así que esto debería funcionar:

<div className={"btn-group pull-right " + (this.props.showBulkActions ? 'show' : 'hidden')}>

Tenga en cuenta el espacio después de "pull-right". No desea proporcionar accidentalmente la clase "pull-rightshow" en lugar de "pull-right show". También los paréntesis deben estar allí.

spitfire109
fuente
3
¡Gracias! Tuve que modificarlo ligeramente porque, por alguna razón, no estaba generando btn-group pull-right en absoluto. Solo mostrar u ocultar.
apexdodge
Esto es particularmente útil en ciertos casos donde classnamespodría no ser apropiado. Si está en su renderfunción y tiene una map, es posible que solo sepa si desea agregar una clase en el momento en que la está procesando, por lo que esta respuesta es bastante útil para eso.
Dave Cooper el
Gran alternativa en lugar de tener un montón de plantillas condicionales en su render o retorno
devonj
@apexdodge qué modificación tuvo que hacer. Tengo el mismo problema.
RamY
1
@RamY Una forma es poner todas las clases dentro del condicional this.props.showBulkActions ? 'btn-group pull-right show' : 'btn-group pull-right hidden'). No es elegante pero funciona.
Ian
87

Como otros han comentado, la utilidad de nombres de clase es el enfoque actualmente recomendado para manejar nombres de clases CSS condicionales en ReactJs.

En su caso, la solución se verá así:

var btnGroupClasses = classNames(
  'btn-group',
  'pull-right',
  {
    'show': this.props.showBulkActions,
    'hidden': !this.props.showBulkActions
  }
);

...

<div className={btnGroupClasses}>...</div>

Como nota al margen, le sugiero que intente evitar usar ambos showy las hiddenclases, por lo que el código podría ser más simple. Lo más probable es que no necesite establecer una clase para que algo se muestre de forma predeterminada.

Diego V
fuente
11
¿Podría dar más detalles sobre la utilidad classNames como el "enfoque recomendado actualmente"? ¿Está eso capturado en algún documento de buenas prácticas bien considerado en alguna parte? ¿O simplemente el boca a boca alrededor de React y classNamesen este momento?
Alexander Nied
66
@anied Al momento de escribir esto, se recomendó en la documentación oficial de React: web.archive.org/web/20160602124910/http://facebook.github.io:80/…
Diego V
3
Todavía se menciona en la última documentación : " Si a menudo te encuentras escribiendo código como este, el paquete de nombres de clase puede simplificarlo " .
Franklin Yu
66

Si está utilizando un transpilador (como Babel o Traceur), puede utilizar las nuevas " cadenas de plantilla " de ES6 .

Aquí está la respuesta de @ spitfire109, modificada en consecuencia:

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'shown' : 'hidden'}`}>

Este enfoque le permite hacer cosas ordenadas como esa, representando s-is-showno s-is-hidden:

<div className={`s-${this.props.showBulkActions ? 'is-shown' : 'is-hidden'}`}>
Bertrand
fuente
20
Tenga cuidado con el segundo enfoque, especialmente en bases de código grandes, ya que hace que las cadenas de clase sean menos greppables. Por ejemplo, si alguien busca s-is-showno está s-is-hiddenen la base de código, no encontrará este código.
marca el
15

Puede usar aquí los literales de cadena

const Angle = ({show}) => {

   const angle = `fa ${show ? 'fa-angle-down' : 'fa-angle-right'}`;

   return <i className={angle} />
}
Musa
fuente
9

Gastando en la buena respuesta de @ spitfire109, uno podría hacer algo como esto:

rootClassNames() {
  let names = ['my-default-class'];
  if (this.props.disabled) names.push('text-muted', 'other-class');

  return names.join(' ');
}

y luego dentro de la función render:

<div className={this.rootClassNames()}></div>

mantiene el jsx corto

escamoso
fuente
8

O use npm classnames . Es muy fácil y útil especialmente para construir la lista de clases.

Pencilcheck
fuente
8

En caso de que solo necesite un nombre de clase opcional:

<div className={"btn-group pull-right " + (this.props.showBulkActions ? "show" : "")}>
Eugene Chybisov
fuente
1
Esto agregará falseclase cuando la condición falle.
RA.
6

Puede usar matrices ES6 en lugar de nombres de clase. La respuesta se basa en el artículo del Dr. Axel Rauschmayer: Agregar condicionalmente entradas dentro de Array y literales de objeto .

<div className={[
                 "classAlwaysPresent", 
                 ...Array.from(condition && ["classIfTrue"])
                ].join(" ")} />
Tudor Morar
fuente
por favor amplíe esto, ¿cuál es la condición?
mibbit
condición constante = (1 === 1);
Tudor Morar
5

2019:

Reaccionar es un lago con muchas utilidades. Pero no necesitas ningún npmpaquete para eso. simplemente cree en algún lugar la función classnamesy llámela cuando lo necesite;

function classnames(obj){
  return Object.entries(obj).filter( e => e[1] ).map( e=>e[0] ).join(' ');
}

o

function classnames(obj){
 return Object.entries(obj).map( ([k,v]) => v?k:'' ).join(' ');
}

ejemplo

  stateClass= {
    foo:true,
    bar:false,
    pony:2
  }
  classnames(stateClass) // return 'foo pony'

 <div className="foo bar {classnames(stateClass)}"> some content </div>

Solo por inspiración

declarar elemento auxiliar y usarlo togglemétodo

(DOMToken​List)classList.toggle(class,condition)

ejemplo:

const classes = document.createElement('span').classList; 

function classstate(obj){
  for( let n in obj) classes.toggle(n,obj[n]);
 return classes; 
}
pery mimon
fuente
4

Solución más elegante, que es mejor para el mantenimiento y la legibilidad:

const classNames = ['js-btn-connect'];

if (isSelected) { classNames.push('is-selected'); }

<Element className={classNames.join(' ')}/>
Nate Ben
fuente
3

puedes usar esto:

<div className={"btn-group pull-right" + (this.props.showBulkActions ? ' show' : ' hidden')}>
AmirBll
fuente
2

Esto funcionaría para ti

var TopicNav = React.createClass({
render: function() {

let _myClasses = `btn-group pull-right {this.props.showBulkActions?'show':'hidden'}`;

return (
            ...
            <div className={_myClasses}>
               ...
            </div>
    );
  }
});
Manoj Amalraj
fuente
1

Puede usar este paquete npm. Maneja todo y tiene opciones para clases estáticas y dinámicas basadas en una variable o una función.

// Support for string arguments
getClassNames('class1', 'class2');

// support for Object
getClassNames({class1: true, class2 : false});

// support for all type of data
getClassNames('class1', 'class2', null, undefined, 3, ['class3', 'class4'], { 
    class5 : function() { return false; },
    class6 : function() { return true; }
});

<div className={getClassNames('show', {class1: true, class2 : false})} /> // "show class1"
Tushar Sharma
fuente
1

Según el valor de this.props.showBulkActionsusted, puede cambiar de clase dinámicamente de la siguiente manera.

<div ...{...this.props.showBulkActions 
? { className: 'btn-group pull-right show' } 
: { className: 'btn-group pull-right hidden' }}>
Vladimir Trifonov
fuente
1

Me gustaría agregar que también puede usar un contenido variable como parte de la clase

<img src={src} alt="Avatar" className={"img-" + messages[key].sender} />

El contexto es un chat entre un bot y un usuario, y los estilos cambian dependiendo del remitente, este es el resultado del navegador:

<img src="http://imageurl" alt="Avatar" class="img-bot">
JC
fuente
1

Esto es útil cuando tiene más de una clase para agregar. Puede unir todas las clases en una matriz con un espacio.

const visibility = this.props.showBulkActions ? "show" : ""
<div className={["btn-group pull-right", visibility].join(' ')}>
kooskoos
fuente
1

Reemplazar:

<div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}">`

con:

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'show' : 'hidden'}`}
Amit Agarwal
fuente
0

Referencia a la respuesta de fuego de @split, podemos actualizarla con literales de plantilla, que es más legible. Para referencia Checkout javascript literal de plantilla

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'show' : 'hidden'}`}>
Akhil Aravind
fuente
0

Encontré esto que explica cómo hacerlo con un ternario y con la Biblioteca de nombres de clase

chachan
fuente