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í?


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


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.


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

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

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



8

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

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

1
Esto agregará falseclase cuando la condición falle.
RA.


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

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

3

puedes usar esto:

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

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

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"

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

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

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

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


0

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

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.