useId
est un Hook React permettant de générer des identifiants uniques qui peuvent être passés comme attributs d’accessibilité.
const id = useId()
Référence
useId()
Appelez useId
à la racine de votre composant pour générer un identifiant unique :
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
Voir d’autres exemples ci-dessous.
Paramètres
useId
ne prend aucun paramètre.
Valeur renvoyée
useId
renvoie un identifiant textuel unique, associé à cet appel useId
précis au sein de ce composant.
Limitations
-
useId
est un Hook, vous pouvez donc uniquement l’appeler à la racine de votre composant ou de vos propres Hooks. Vous ne pouvez pas l’appeler à l’intérieur de boucles ou de conditions. Si nécessaire, extrayez un nouveau composant et déplacez l’état dans celui-ci. -
useId
ne doit pas être utilisé pour générer des clés dans une liste. Les clés devraient toujours être basées sur vos données.
Utilisation
Générer des identifiants uniques pour les attributs d’accessibilité
Appelez useId
à la racine de votre composant pour générer un identifiant unique :
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
Vous pouvez ensuite transmettre l’identifiant généré à différents attributs :
<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>
</>
Prenons un exemple pour mieux saisir l’utilité de cette méthode.
Les attributs d’accessibilité HTML tels que aria-describedby
vous permettent de spécifier que deux balises sont liées l’une à l’autre. Par exemple, vous pouvez spécifier qu’un élément (tel qu’un champ de saisie) est décrit par un autre élément (tel qu’un paragraphe).
En HTML classique, vous l’écririez comme suit :
<label>
Mot de passe :
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
Le mot de passe doit contenir au moins 18 caractères
</p>
Cependant, définir des ID en dur comme ça constitue une mauvaise pratique en React. Un composant pourrait être présent plusieurs fois sur la page—mais les ID doivent être uniques ! Au lieu d’utiliser un identifiant fixe, générez un identifiant unique avec useId
:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Mot de passe :
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
Le mot de passe doit contenir au moins 18 caractères
</p>
</>
);
}
Désormais, même si PasswordField
est utilisé plusieurs fois à l’écran, les identifiants générés ne rentreront pas en conflit.
import { useId } from 'react'; function PasswordField() { const passwordHintId = useId(); return ( <> <label> Mot de passe : <input type="password" aria-describedby={passwordHintId} /> </label> <p id={passwordHintId}> Le mot de passe doit contenir au moins 18 caractères </p> </> ); } export default function App() { return ( <> <h2>Choisissez un mot de passe</h2> <PasswordField /> <h2>Confirmez le mot de passe</h2> <PasswordField /> </> ); }
Regardez cette vidéo pour comprendre en quoi ça améliore l’expérience des utilisateurs de technologies d’assistance.
En détail
Vous vous demandez peut-être pourquoi il est préférable d’utiliser useId
plutôt que d’incrémenter une variable globale, du genre nextId++
.
Le principal avantage de useId
tient à ce que React garantit son bon fonctionnement dans le rendu serveur. Lors du rendu serveur, vos composants produisent du HTML. Plus tard, sur le client, le processus d’hydratation attache vos gestionnaires d’événements au HTML généré. Pour que l’hydratation fonctionne, le résultat du code client doit correspondre au HTML du serveur.
Il est très difficile de garantir ça avec un compteur incrémental, car l’ordre dans lequel les Composants Client sont hydratés peut ne pas correspondre à l’ordre dans lequel le code HTML du serveur est émis. En appelant useId
, vous vous assurez que l’hydratation fonctionnera et que la sortie correspondra entre le serveur et le client.
Dans React, useId
est généré à partir du « chemin de parents » du composant appelant. C’est pourquoi, si l’arbre du client et celui du serveur sont identiques, ce « chemin » correspondra quel que soit l’ordre de rendu.
Générer des identifiants pour plusieurs éléments liés
Si vous devez attribuer des identifiants à plusieurs éléments liés, vous pouvez appeler useId
pour leur attribuer un préfixe commun :
import { useId } from 'react'; export default function Form() { const id = useId(); return ( <form> <label htmlFor={id + '-firstName'}>Prénom :</label> <input id={id + '-firstName'} type="text" /> <hr /> <label htmlFor={id + '-lastName'}>Nom de famille :</label> <input id={id + '-lastName'} type="text" /> </form> ); }
Vous évitez ainsi d’appeler useId
pour chaque élément nécessitant un identifiant unique.
Préciser un préfixe partagé pour tous les identifiants générés
Si vous affichez plusieurs applications React indépendantes sur une même page, passez identifierPrefix
comme option à vos appels createRoot
ou hydrateRoot
. Ça garantira que les identifiants générés par les deux applications distinctes ne seront jamais en conflit, car chaque identifiant généré avec useId
commencera par le préfixe distinct que vous aurez spécifié.
import { createRoot } from 'react-dom/client'; import App from './App.js'; import './styles.css'; const root1 = createRoot(document.getElementById('root1'), { identifierPrefix: 'my-first-app-' }); root1.render(<App />); const root2 = createRoot(document.getElementById('root2'), { identifierPrefix: 'my-second-app-' }); root2.render(<App />);
Utiliser le même préfixe d’identifiant côtés client et serveur
Si vous injectez plusieurs applis React distinctes sur la même page et que certaines de ces applis bénéficient d’un rendu côté serveur, assurez-vous que le identifierPrefix
passé à hydrateRoot
côté client est identique au identifierPrefix
passé aux API côté serveur, telles que renderToPipeableStream
.
// Serveur
import { renderToPipeableStream } from 'react-dom/server';
const { pipe } = renderToPipeableStream(
<App />,
{ identifierPrefix: 'react-app1' }
);
// Client
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(
domNode,
reactNode,
{ identifierPrefix: 'react-app1' }
);
Vous n’avez besoin de passer un identifierPrefix
que si vous avez plus d’une appli React sur la page.