React Js appliquant conditionnellement des attributs de classe


334

Je veux afficher et masquer ce groupe de boutons de manière conditionnelle en fonction de ce qui est passé du composant parent qui ressemble à ceci:

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

Cependant, rien ne se passe avec les {this.props.showBulkActions? 'show': 'caché'}. Suis-je en train de faire quelque chose de mal ici?


Vous pouvez également envisager de réagir-bootstrap , car cela résume certains éléments de la classe dans les propriétés des composants, ce qui rend ce que vous essayez de faire un peu plus facile.
Dancrumb

Réponses:


591

Les accolades sont à l'intérieur de la chaîne, elle est donc évaluée en tant que chaîne. Ils doivent être à l'extérieur, donc cela devrait fonctionner:

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

Notez l'espace après "tirer vers la droite". Vous ne voulez pas fournir accidentellement la classe "pull-rightshow" au lieu de "pull-right show". Les parenthèses doivent également être présentes.


3
Merci! J'ai dû le modifier légèrement parce que pour une raison quelconque, il ne produisait pas du tout le droit d'extraction du groupe btn. Afficher ou masquer.
apexdodge

Cela est particulièrement utile dans certains cas où cela classnamespourrait ne pas être approprié. Si vous êtes dans votre renderfonction et que vous en avez un map, vous ne savez peut-être que si vous voulez ajouter une classe au moment où vous la rendez, donc cette réponse est très utile pour cela.
Dave Cooper

excellente alternative au lieu d'avoir un tas de modèles conditionnels dans votre rendu ou retour
devonj

@apexdodge quelle modification vous avez dû faire. J'ai le même problème.
RamY

1
@RamY Une façon consiste à mettre toutes les classes à l'intérieur du conditionnel this.props.showBulkActions ? 'btn-group pull-right show' : 'btn-group pull-right hidden'). Pas élégant mais ça marche.
Ian

87

Comme d'autres l'ont commenté, les noms de classe utilitaire est l'approche actuellement recommandée pour gérer les noms de classe CSS conditionnels dans ReactJs.

Dans votre cas, la solution ressemblera à:

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

...

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

En guise de remarque, je vous suggère d'essayer d'éviter d'utiliser à la fois les classes showet hidden, afin que le code puisse être plus simple. Vous n'avez probablement pas besoin de définir une classe pour que quelque chose soit affiché par défaut.


11
Pourriez-vous préciser que l'utilitaire classNames est "l'approche actuellement recommandée"? Cela figure-t-il quelque part dans un document de bonnes pratiques bien considéré? Ou tout simplement le bouche à oreille autour de React et classNamesen ce moment?
Alexander Nied

6
@anied Au moment de la rédaction, il était recommandé dans la documentation officielle de React: web.archive.org/web/20160602124910/http://facebook.github.io:80/…
Diego V

3
Il est toujours mentionné dans la dernière documentation : " Si vous vous retrouvez souvent à écrire du code comme celui-ci, le package des noms de classe peut le simplifier. "
Franklin Yu

66

Si vous utilisez un transpilateur (comme Babel ou Traceur), vous pouvez utiliser les nouvelles " chaînes de modèle " ES6 .

Voici la réponse de @ spitfire109, modifiée en conséquence:

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

Cette approche vous permet de faire des choses intéressantes comme ça, en rendant soit s-is-shownou s-is-hidden:

<div className={`s-${this.props.showBulkActions ? 'is-shown' : 'is-hidden'}`}>

20
Soyez prudent avec la deuxième approche, en particulier dans les grandes bases de code, car elle rend les chaînes de classe moins acceptables. Par exemple, si quelqu'un recherche s-is-shownou s-is-hiddendans la base de code, il ne trouvera pas ce code.
marquer

15

Vous pouvez utiliser ici des littéraux de chaîne

const Angle = ({show}) => {

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

   return <i className={angle} />
}

9

En dépensant sur la bonne réponse de @ spitfire109, on pourrait faire quelque chose comme ceci:

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

  return names.join(' ');
}

puis dans la fonction de rendu:

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

garde le jsx court



8

Dans le cas où vous aurez besoin d'un seul nom de classe facultatif:

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

1
Cela ajoutera la falseclasse lorsque la condition échoue.
RA.


5

2019:

React est un lac de nombreux services publics. Mais vous n'avez besoin d'aucun npmpackage pour cela. créez quelque part la fonction classnameset appelez-la quand vous en avez besoin;

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

ou

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

exemple

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

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

Juste pour l'inspiration

déclarer l'élément d'assistance et utilisé la toggleméthode

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

exemple:

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

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

4

Solution plus élégante, meilleure pour la maintenance et la lisibilité:

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

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

<Element className={classNames.join(' ')}/>

3

vous pouvez utiliser ceci:

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

2

Cela fonctionnerait pour vous

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

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

return (
            ...
            <div className={_myClasses}>
               ...
            </div>
    );
  }
});

1

Vous pouvez utiliser ce package npm. Il gère tout et dispose d'options pour les classes statiques et dynamiques basées sur une variable ou une fonction.

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

En fonction de la valeur de this.props.showBulkActionsvous pouvez changer de classe dynamiquement comme suit.

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

1

Je voudrais ajouter que vous pouvez également utiliser un contenu variable dans le cadre de la classe

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

Le contexte est un chat entre un bot et un utilisateur, et les styles changent en fonction de l'expéditeur, voici le résultat du navigateur:

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

1

Ceci est utile lorsque vous avez plusieurs classes à ajouter. Vous pouvez joindre toutes les classes dans un tableau avec un espace.

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

1

Remplacer:

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

avec:

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

0

Référence à @split fire answer, nous pouvons le mettre à jour avec des littéraux de modèle, ce qui est plus lisible, pour référence Checkout javascript template literal

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

0

J'ai trouvé cela qui explique comment le faire avec un ternaire et avec la bibliothèque de noms de classes

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.