Un Fragment React permet à un composant de renvoyer plusieurs éléments sans les envelopper dans une <div> supplémentaire. Écrivez <> avant le premier élément et </> après le dernier, et React place les éléments directement dans le parent, sans nœud propre dans la page.
Chaque Greeting renvoie un titre et un paragraphe côte à côte. Supprimez les lignes <> et </> et l'aperçu affiche une erreur de build à la place, car la fonction essaie maintenant de renvoyer deux valeurs.
Pourquoi un composant a besoin d'une seule racine
Le JSX est une façon plus agréable d'écrire des appels de fonction. <h2>Hi</h2> se compile à peu près en jsx('h2', { children: 'Hi' }), une seule expression. Une instruction return ne peut renvoyer qu'une valeur, donc deux balises sœurs sans rien autour reviennent à écrire return a b : le compilateur s'arrête avec "Adjacent JSX elements must be wrapped in an enclosing tag".
Avant l'existence des fragments, la solution était une <div> enveloppe. Cela fonctionne, mais la div est un vrai élément. Elle apparaît dans le DOM, participe à la mise en page CSS, et certains parents ne l'acceptent pas du tout comme enfant. Un fragment respecte la règle de la racine unique puis disparaît.
Vous pouvez vérifier qu'il n'ajoute rien. L'exemple ci-dessous affiche les deux mêmes éléments via un fragment et via une div, puis compte les enfants directs de chaque conteneur.
La console affiche 2 pour le fragment, les deux spans, et 1 pour la div, qui les enveloppe. Dans un conteneur flex ou grid, cette différence décide si les spans sont disposés comme des éléments distincts ou regroupés en un seul.
Syntaxe courte et composant Fragment
Il existe deux façons d'écrire un fragment, et elles se compilent en la même chose :
import { Fragment } from 'react';
// Short syntax, no import needed
<>
<dt>React</dt>
<dd>A library for building user interfaces</dd>
</>
// Long form
<Fragment>
<dt>React</dt>
<dd>A library for building user interfaces</dd>
</Fragment>
Utilisez <>...</> presque partout. Passez à <Fragment> dans un seul cas : quand le fragment a besoin d'une key. La syntaxe courte n'accepte pas d'attributs, donc <key={id}> n'est pas du JSX valide. Vous verrez aussi <React.Fragment> dans du code ancien ; c'est le même composant, atteint via l'import par défaut React.
Fragments avec key dans les listes
Quand vous affichez une liste avec map, chaque élément a besoin d'une key pour que React puisse le suivre d'un rendu à l'autre (la page sur les listes et les keys explique pourquoi). Si chaque élément est un groupe d'éléments plutôt qu'un seul, la key se place sur le fragment, il vous faut donc la forme longue.
Une liste de définitions est le cas typique : chaque entrée est un <dt> et un <dd>, et un <dl> doit les contenir directement.
Cliquez sur Reverse et les paires échangent leurs places comme des blocs entiers, car chaque paire a sa propre key. Une <div> enveloppe autour de chaque paire accepterait aussi une key, et c'est du HTML valide dans un dl, mais elle ajoute au balisage un troisième niveau qu'un fragment évite.
Fragments dans les tableaux
Les tableaux sont l'endroit où une enveloppe superflue fait le plus de dégâts. Un <tr> attend des cellules <td> et <th> comme enfants directs. Si un composant qui renvoie plusieurs cellules les enveloppe dans une <div>, le navigateur traite la div comme une cellule bizarre et les cellules qu'elle contient ne s'alignent plus avec l'en-tête.
La ligne avec fragment a son prix sous Price et son stock sous Stock. Dans la ligne avec div, les deux cellules sont tassées dans la colonne Price et la colonne Stock est vide. En développement, React affiche aussi un avertissement indiquant qu'une <div> ne peut pas être enfant d'un <tr> ; l'aperçu fonctionne comme un build de production et saute donc cette vérification, et c'est la mise en page cassée que vous voyez ici. Avec le rendu serveur, la même erreur peut aussi provoquer des erreurs d'hydratation, car l'analyseur HTML du navigateur déplace la div mal placée.
La même règle s'applique à <ul> et <ol>, qui doivent contenir des éléments <li>, et à <select>, qui doit contenir des éléments <option>. Chaque fois qu'un composant renvoie des morceaux qui doivent aller directement dans un tel parent, renvoyez un fragment.
Fragments ou tableaux
Un composant peut aussi renvoyer un tableau d'éléments, et React les affiche dans l'ordre comme un fragment. Chaque élément d'un tableau renvoyé a besoin de sa propre key, comme le résultat de map, car React traite le tableau comme une liste :
function Cells() {
return [<td key="price">$4</td>, <td key="stock">In stock</td>];
}
Cela fonctionne, mais c'est plus chargé : des virgules entre les éléments, une key sur chacun, et un crochet facile à rater quand le balisage grossit. Utilisez un fragment pour un groupe fixe d'éléments, et gardez les tableaux pour ce qu'ils sont naturellement, le résultat d'un parcours de données.
Ce qu'un fragment ne peut pas faire
Comme un fragment n'affiche aucun élément, il n'a nulle part où placer une classe, un style, un gestionnaire d'événement ou une ref. <Fragment className="row"> ne fait rien d'utile, et la seule prop que React lit sur un fragment est key. Quand vous devez styliser le groupe ou écouter les clics dessus, il vous faut finalement un vrai élément, et c'est très bien : choisissez-en un qui est valide à cet endroit, comme un <tbody> pour grouper des lignes ou un <li> pour contenir un élément de liste.
Un fragment fonctionne partout où un élément fonctionne, y compris dans le rendu conditionnel : {show && <>...</>} affiche ou masque tout le groupe d'un coup.
Questions fréquentes
Qu'est-ce qu'un Fragment dans React ?
Un Fragment est une enveloppe qui permet à un composant de renvoyer plusieurs éléments en une seule valeur sans ajouter de nœud DOM. <><h1 /><p /></> place le h1 et le p directement dans le parent.
Quelle est la différence entre <> et <Fragment> ?
Ils produisent la même chose. <>...</> est la syntaxe courte. <Fragment> est la forme longue que vous importez depuis react, et c'est la seule qui accepte une key, nécessaire quand vous affichez des fragments dans une liste.
Pourquoi utiliser un Fragment plutôt qu'une div ?
Une div est un vrai élément. Elle peut casser des mises en page qui attendent des enfants directs (conteneurs flex et grid, ul, table, tr) et ajoute du bruit dans le DOM. Un Fragment n'ajoute rien.
Un Fragment peut-il avoir un className ou un onClick ?
Non. Un Fragment n'affiche aucun élément, il n'y a donc rien sur quoi placer une classe, un style ou un gestionnaire d'événement. La seule prop qu'il accepte est key. Si vous avez besoin de l'un d'eux, utilisez un vrai élément.
Pourquoi ai-je l'erreur "Adjacent JSX elements must be wrapped in an enclosing tag" ?
Un composant a renvoyé deux éléments frères sans rien autour. Le JSX se compile en une seule expression, entourez donc les éléments frères de <>...</>.