Affichage conditionnel

Vos composants devront souvent produire des affichages distincts en fonction de certaines conditions. Dans React, vous pouvez produire du JSX conditionnellement en utilisant des syntaxes JavaScript telles que les instructions if et les opérateurs && et ? :.

Vous allez apprendre

  • Comment renvoyer du JSX différent en fonction d’une condition
  • Comment inclure ou exclure conditionnellement un bout de JSX
  • Les raccourcis syntaxiques habituels que vous rencontrerez dans les bases de code utilisant React

Renvoi conditionnel de JSX

Disons que vous avez un composant PackingList qui affiche plusieurs Items que vous pouvez marquer comme placés ou non dans les bagages :

function Item({ name, isPacked }) {
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

Remarquez que certains composants Item ont leur prop isPacked à true plutôt qu’à false. Vous souhaitez ajouter une coche (✔) aux objets pour lesquels isPacked={true}.

Vous pourriez écrire ça sous forme d’instruction if/else, comme ceci :

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

Si la prop isPacked vaut true, ce code renverra un arbre JSX différent. Suite à cette modification, certains des éléments auront une coche à la fin :

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

Essayez de modifier le balisage renvoyé dans chaque cas, et voyez comme le résultat évolue !

Notez que vous avez créé des branches logiques en utilisant les instructions if et else de JavaScript. Dans React, le flux de contrôle (tel que les conditions) est géré par JavaScript.

Conditionnellement ne rien renvoyer avec null

Dans certains cas, vous ne voudrez rien renvoyer du tout. Disons par exemple que vous ne souhaitez pas afficher les objets déjà mis dans les bagages. Un composant doit pourtant bien renvoyer quelque chose. Dans un tel cas, vous pouvez renvoyer null :

if (isPacked) {
return null;
}
return <li className="item">{name}</li>;

Si isPacked est à true, le composant ne renverra rien, donc null. Autrement, il renverra le JSX à afficher.

function Item({ name, isPacked }) {
  if (isPacked) {
    return null;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

En pratique, les composants ne renvoient pas souvent null parce que ça peut surprendre le développeur qui essaierait de l’afficher. Vous préférerez généralement inclure ou exclure le composant dans le JSX du composant parent. Voici comment faire ça !

Inclure du JSX conditionnellement

Dans l’exemple précédent, vous contrôliez quel arbre JSX renvoyer (si tant est qu’il y en ait un !) depuis le composant. Vous avez peut-être remarqué une légère duplication dans l’affichage produit. Ce JSX :

<li className="item">{name}</li>

est très similaire à

<li className="item">{name}</li>

Les deux branches conditionnelles renvoient <li className="item">...</li> :

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

Même si cette duplication n’est pas dangereuse, elle complexifie la maintenance de votre code. Et si vous vouliez changer le className ? Vous devriez le mettre à jour à deux endroits de votre code ! Dans un tel cas, vous pourriez plutôt inclure un bout de JSX de façon conditionnelle pour rendre votre code plus DRY.

Opérateur (ternaire) conditionnel (? :)

JavaScript dispose d’une syntaxe compacte pour écrire une expression conditionnelle : l’opérateur conditionnel, également appelé « ternaire » :

Au lieu de ceci :

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

Vous pouvez plutôt écrire ceci :

return (
<li className="item">
{isPacked ? name + ' ✔' : name}
</li>
);

Vous pouvez le lire comme suit : « si isPacked est vrai, alors (?) affiche name + ' ✔', sinon (:) affiche name ».

En détail

Ces deux exemples sont-ils vraiment équivalents ?

Si vous êtes habitué·e à la programmation orientée objet, vous vous dites peut-être que les deux exemples ci-dessus sont subtilement différents parce que l’un d’eux pourrait créer deux « instances » de <li>. mais les éléments JSX ne sont pas des « instances » car ils ne contiennent aucun état interne et ne sont pas de véritables nœuds DOM. Il s’agit de descriptifs légers, comme des plans de construction. De sorte que ces deux exemples sont effectivement parfaitement équivalents. La page Préserver et réinitialiser l’état explore en détail ces aspects.

Disons maintenant que vous souhaitez enrober le texte d’un objet mis en bagages par une autre balise HTML, telle que <del>, pour le biffer. Vous pouvez ajouter des sauts de lignes et des parenthèses, pour qu’il soit plus facile d’imbriquer davantage de JSX dans chacun des cas :

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {isPacked ? (
        <del>
          {name + ' ✔'}
        </del>
      ) : (
        name
      )}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

Ce style fonctionne bien pour des conditions simples, mais utilisez-le avec modération. Si vos composants deviennent difficiles à lire en raison de trop de balisages conditionnels imbriqués, envisagez d’extraire des composants enfants pour nettoyer tout ça. Dans React, le balisage fait partie de votre code, vous pouvez donc recourir à des variables et des fonctions pour nettoyer les expressions complexes.

L’opérateur logique ET (&&)

Un autre raccourci que vous rencontrerez souvent utilise l’opérateur ET logique (&&) de JavaScript. Dans les composants React, il apparaît souvent lorsque vous souhaitez afficher du JSX lorsqu’une condition est remplie, ou ne rien afficher dans le cas contraire. Avec &&, vous pouvez afficher conditionnellement la coche seulement si isPacked vaut true :

return (
<li className="item">
{name} {isPacked && '✔'}
</li>
);

Vous pouvez le lire comme suit : « si isPacked est vrai, alors (&&) affiche la coche, sinon n’affiche rien ».

Le voici en action :

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

Une expression && JavaScript renvoie la valeur de son opérande à droite (dans notre cas, la coche) si l’opérande à gauche (notre condition) vaut true. Mais si la condition vaut false, React considèrera false comme un « trou » dans l’arbre JSX, tout comme null ou undefined, et n’affichera rien à cet endroit.

Piège

Ne mettez pas des nombres à gauche de &&.

Pour tester la condition, JavaScript convertit automatiquement l’opérande de gauche en booléen. Seulement voilà, si l’opérande de gauche vaut 0, alors l’expression entière vaudra 0, et React sera ravi d’afficher 0 plutôt que rien.

Ainsi, une erreur commune consiste à écrire du code du genre messageCount && <p>Nouveaux messages</p>. On peut facilement supposer que ça n’affichera rien si messageCount vaut 0, mais en fait ça affichera le 0 lui-même !

Pour éviter ça, assurez-vous que l’opérande de gauche est un booléen : messageCount > 0 && <p>Nouveaux messages</p>.

Affecter conditionnellement du JSX à une variable

Lorsque les raccourcis rendent votre code compliqué à lire, essayez d’utiliser plutôt une instruction if et une variable. Vous pouvez réaffecter les variables déclarées avec let, alors commencez par le contenu que vous souhaiteriez afficher par défaut, comme le nom :

let itemContent = name;

Utilisez une instruction if pour réaffecter une expression JSX à itemContent si isPacked vaut true :

if (isPacked) {
itemContent = name + " ✔";
}

Les accolades « ouvrent une fenêtre » vers JavaScript. Incorporez la variable entre accolades dans l’arbre JSX renvoyé, ce qui y imbriquera l’expression précédemment calculée :

<li className="item">
{itemContent}
</li>

Ce style est certes le plus verbeux, mais au final le plus flexible. Le voici en action :

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✔";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

Comme précédemment, ça ne marche pas seulement pour le texte, mais pour n’importe quel JSX aussi :

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = (
      <del>
        {name + " ✔"}
      </del>
    );
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}

Si vous n’êtes pas à l’aise avec JavaScript, cette variété de styles peut vous sembler intimidante au premier abord. Ceci dit, apprendre ces différents styles vous aidera à lire et écrire n’importe quel code JavaScript — pas seulement des composants React ! Choisissez le style que vous préférez pour commencer, puis revenez sur cette page si vous oubliez quels autres styles marchent aussi.

En résumé

  • Dans React, vous contrôlez les branches logiques avec JavaScript.
  • Vous pouvez renvoyer une expression JavaScript conditionnellement avec une instruction if.
  • Vous pouvez sauver conditionnellement du JSX dans une variable puis l’inclure dans un autre bout de JSX grâce aux accolades.
  • En JSX, {cond ? <A /> : <B />} signifie « si cond, affiche <A />, sinon <B /> ».
  • En JSX, {cond && <A />} signifie « si cond, affiche <A />, sinon rien ».
  • Les raccourcis sont fréquents, mais vous n’êtes pas obligé·e de les utiliser si vous préférez de simples if.

Défi 1 sur 3 ·
Afficher un icône pour les objets non traités avec ? :

Utilisez l’opérateur conditionnel (cond ? a : b) pour afficher ❌ si isPacked ne vaut pas true.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Liste d’affaires de Sally Ride</h1>
      <ul>
        <Item
          isPacked={true}
          name="Combinaison spatiale"
        />
        <Item
          isPacked={true}
          name="Casque à feuille d’or"
        />
        <Item
          isPacked={false}
          name="Photo de Tam"
        />
      </ul>
    </section>
  );
}