Pour afficher une liste en React, appelez map() sur un tableau et renvoyez un morceau de JSX pour chaque élément. Donnez à l'élément le plus extérieur de chaque entrée une prop key avec une valeur qui identifie cet élément, en général son identifiant, pour que React puisse distinguer les éléments quand la liste change.
Ajoutez { id: 'dat', name: 'Date', price: 4 } au tableau et une quatrième ligne apparaît. Le JSX n'a pas de syntaxe de boucle propre : map renvoie un tableau d'éléments, et React affiche un tableau en affichant chaque élément dans l'ordre.
Afficher des tableaux avec map
map appelle votre fonction une fois par élément et rassemble les résultats dans un nouveau tableau. Entre les accolades du JSX, ce tableau n'est qu'une valeur : vous pouvez donc faire le map directement dans le balisage, comme ci-dessus, ou construire le tableau d'abord :
const items = fruits.map((fruit) => <li key={fruit.id}>{fruit.name}</li>);
return <ul>{items}</ul>;
Deux détails piègent souvent. Si vous utilisez des accolades dans la fonction fléchée, il vous faut un return : fruits.map((f) => { return <li key={f.id}>{f.name}</li>; }). Sans lui, la fonction renvoie undefined et la liste est vide. Et la key se place sur l'élément renvoyé par map, pas sur un élément à l'intérieur. Si l'élément est un composant, placez la key sur le composant : <FruitRow key={fruit.id} fruit={fruit} />.
Filter, puis map
Pour afficher une partie des éléments, filtrez d'abord le tableau puis parcourez le résultat avec map. Chaque méthode fait une seule chose, et la chaîne se lit comme la phrase « les fruits qui correspondent, sous forme d'éléments de liste ».
Tapez er dans le champ de recherche et la liste se réduit à Eraser, Ruler et Stapler ; cochez In stock only et Ruler disparaît aussi. La liste filtrée est calculée pendant le rendu à partir des deux éléments d'état, il n'y a donc pas de second tableau dans l'état à garder synchronisé. visible.length === 0 && est un usage sûr de &&, car la comparaison est un vrai booléen (la page sur le rendu conditionnel montre ce qui se passe avec un 0 seul).
À quoi servent les keys
Quand une liste refait un rendu, React compare le nouveau tableau d'éléments au précédent. Les keys lui permettent de les associer : l'élément avec la key 3 maintenant est l'élément qui avait la key 3 avant, même s'il a bougé. React garde le nœud DOM de cet élément et l'état de son composant, et ne déplace ou ne met à jour que ce qui a changé. Les éléments avec de nouvelles keys sont créés, et ceux dont la key a disparu sont retirés.
Sans keys, React ne peut associer les éléments que par leur position. Cela va tant que rien ne bouge, et devient faux dès que quelque chose bouge.
Pourquoi les keys d'index cassent
map passe l'index en second argument, donc key={index} est tentant. L'index décrit une position, pas un élément. Insérez un élément en tête et l'index de chaque élément se décale d'un cran : React croit alors que l'élément 0 est toujours l'élément 0 et y garde son ancien état.
La démo ci-dessous affiche deux fois la même liste, une fois avec l'index comme key et une fois avec l'identifiant. Chaque ligne a un champ qui garde son propre texte.
Tapez math à côté d'Ada dans les deux listes, puis cliquez sur Add to top. Dans la liste par identifiant, la note reste avec Ada. Dans la liste par index, la note saute sur la nouvelle personne, car le premier champ est toujours le champ en position 0, et la position 0 est maintenant quelqu'un d'autre. Les noms sont corrects dans les deux listes, puisqu'ils viennent des données ; seul l'état qui vit dans le DOM et dans les composants se trompe. Les vraies applications rencontrent ce problème avec les cases à cocher, le focus, les animations et tout composant qui contient un useState.
Les keys d'index ne sont sûres que si toutes ces conditions sont réunies : la liste n'est jamais triée ni filtrée, aucun élément n'est inséré ni retiré ailleurs qu'à la fin, et les éléments n'ont pas d'état propre. Une liste statique de liens de pied de page convient. Tout ce qu'un utilisateur peut modifier, en général non.
D'où viennent les keys
La meilleure key est un identifiant déjà présent dans les données : un ID de base de données, un SKU de produit, un slug, un nom d'utilisateur. Les données venant d'un serveur en ont presque toujours un.
Pour les éléments créés dans le navigateur, donnez à chaque élément un identifiant au moment de sa création et stockez-le avec lui : un compteur, comme dans la démo ci-dessus, ou crypto.randomUUID(). Ne générez jamais la key pendant le rendu :
// Wrong: a new key on every render, so React remounts every item every time
{todos.map((todo) => <Todo key={Math.random()} todo={todo} />)}
// Right: the ID is created once, in the event that adds the item
function addTodo(text) {
setTodos([...todos, { id: crypto.randomUUID(), text }]);
}
Une key qui change à chaque rendu est pire qu'un index : chaque élément est détruit et recréé à chaque fois, les champs perdent le focus pendant la saisie, et rien ne garde son état. La même astuce est utile volontairement : changer la key d'un composant le réinitialise, ce que la page sur useState utilise pour vider un formulaire.
Les keys sont uniques seulement entre éléments frères
Une key doit être unique au sein d'une liste, pas dans toute l'application. Deux listes séparées peuvent réutiliser les mêmes identifiants, car React ne compare les keys qu'entre les enfants d'un même parent.
Les deux sections ont des plats avec les keys 1 et 2, et c'est correct : chaque ul est sa propre liste. Le problème, ce sont les keys en double dans une même liste : React ne peut pas distinguer les éléments en conflit, et quand la liste se met à jour, il peut les dupliquer ou les perdre.
Quand un élément affiche plusieurs éléments frères, comme un <dt> et un <dd>, enveloppez-les dans <Fragment key={item.id}>. La syntaxe courte <> n'accepte pas de key.
L'avertissement « unique key prop »
Si vous omettez la key, React affiche ceci dans la console du navigateur pendant le développement :
Each child in a list should have a unique "key" prop.
Check the render method of `App`.
La seconde ligne nomme le composant dont le rendu a produit la liste, ce qui vous indique quel map corriger. Deux éléments frères avec la même key donnent un autre message, qui commence par "Encountered two children with the same key". L'aperçu de cette page fonctionne comme un build de production, qui saute cette vérification, vous ne verrez donc pas l'avertissement ici même si vous supprimez une key. Supprimez-en une quand même dans le premier exemple : la liste s'affiche toujours, car une key manquante est un risque d'erreur, pas un plantage. Pour corriger l'avertissement, ajoutez une key stable à l'élément renvoyé par map ; ajouter key={index} le fait taire mais ramène le bug montré plus haut.
Notez aussi que key n'est pas transmise à votre composant. Dans FruitRow, props.key vaut undefined. Si le composant a besoin de l'identifiant, passez-le une seconde fois comme prop normale : <FruitRow key={f.id} id={f.id} />.
Questions fréquentes
Pourquoi React a-t-il besoin d'une key sur les éléments d'une liste ?
Les keys indiquent à React quel élément est lequel d'un rendu à l'autre. Quand le tableau change, React associe les anciens et les nouveaux éléments par key, ce qui lui permet de garder l'état et le nœud DOM de chaque élément avec les bonnes données au lieu de deviner selon la position.
Peut-on utiliser l'index du tableau comme key ?
Seulement pour une liste qui ne change jamais d'ordre et dans laquelle on n'insère ni ne retire jamais d'élément au milieu. Si les éléments peuvent bouger, une key d'index lie l'état à la position, et le texte saisi, les cases cochées et le focus se retrouvent sur le mauvais élément.
Que faut-il utiliser comme key ?
Un identifiant qui appartient aux données : un ID de base de données, un SKU de produit, un nom d'utilisateur. Pour les éléments créés dans le navigateur, générez un identifiant une seule fois à la création de l'élément (un compteur ou crypto.randomUUID()), jamais pendant le rendu.
Les keys doivent-elles être uniques dans toute l'application ?
Non. Les keys doivent seulement être uniques parmi les éléments frères d'une même liste. Deux listes différentes peuvent utiliser les mêmes keys.
Un composant peut-il lire sa propre key ?
Non. key est utilisée par React et n'est pas transmise au composant comme prop. Si le composant a besoin de l'identifiant, passez-le à nouveau sous un autre nom, par exemple id={item.id}.
Comment corriger "Each child in a list should have a unique key prop" ?
Ajoutez une key à l'élément le plus extérieur que vous renvoyez depuis map, avec un identifiant stable de l'élément. Si cet élément est un fragment, utilisez <Fragment key={id}>, car <> n'accepte pas de key.