useId
es un Hook de React para generar IDs únicos que se pueden pasar a los atributos de accesibilidad.
const id = useId()
Referencia
useId()
Llama a useId
en el nivel superior de tu componente para generar un ID único:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
Parámetros
useId
no toma ningún parámetro.
Devuelve
useId
devuelve una cadena de ID única asociada con esta llamada useId
llamado en un componente particular.
Advertencias
-
useId
es un Hook, así que solo puedes llamarlo en el nivel superior de tu componente o en tus propios hooks. No puedes llamarlo dentro de bucles o condiciones. Si necesitas hacerlo, extrae un nuevo componente y mueve allí el estado. -
useId
no debe usarse para generar keys en una lista. Las keys deben generarse a partir de tus datos.
Uso
Generación de ID únicos para atributos de accesibilidad
Llama a useId
en el nivel superior de tu componente para generar un ID único:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
A continuación, puedes pasar el ID generado a los diferentes atributos:
<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>
</>
Veamos un ejemplo para ver cuándo es útil.
Atributos de accesibilidad HTML como aria-describedby
te permiten especificar que dos etiquetas están relacionadas entre sí. Por ejemplo, puedes especificar que un determinado elemento (como una entrada de texto) sea descrito por otro elemento (como un párrafo).
En HTML normal, lo escribirías así:
<label>
Password:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
The password should contain at least 18 characters
</p>
Sin embargo, escribir IDs fijos como este no es una buena práctica en React. Un componente puede renderizarse más de una vez en la página, ¡pero los IDs tienen que ser únicos! En lugar de utilizar un ID fijo, puedes generar un ID único con useId
:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Password:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
The password should contain at least 18 characters
</p>
</>
);
}
Ahora, incluso si PasswordField
aparece varias veces en la pantalla, no habrá conflicto entre los IDs generados.
import { useId } from 'react'; function PasswordField() { const passwordHintId = useId(); return ( <> <label> Password: <input type="password" aria-describedby={passwordHintId} /> </label> <p id={passwordHintId}> The password should contain at least 18 characters </p> </> ); } export default function App() { return ( <> <h2>Choose password</h2> <PasswordField /> <h2>Confirm password</h2> <PasswordField /> </> ); }
Mira este video para ver la diferencia en la experiencia de usuario con tecnologías de asistencia.
Profundizar
Puede que te preguntes por qué useId
es mejor que incrementar una variable global como nextId++
.
El principal beneficio de useId
es que React se asegura de que funcione con el renderizado en el servidor. Durante el renderizado en el servidos, tus componentes generan salida HTML. Más tarde, en el cliente, la hidratación adjunta tus controladores de eventos al HTML generado. Para que la hidratación funcione, la salida del cliente debe coincidir con el HTML del servidor.
Esto es muy difícil de garantizar con un contador incremental porque el orden en que se hidratan los Componentes del Cliente puede no coincidir con el orden en que se emitió el HTML del servidor. Al llamar a useId
, te aseguras de que la hidratación funcionará y la salida coincidirá entre el servidor y el cliente.
Dentro de React, useId
se genera a partir de la «ruta del padre» del componente llamado. Esta es la razón por la que, si el cliente y el árbol del servidor son iguales, la «ruta del padre» coincidirá independientemente del orden del renderizado.
Generar IDs para varios elementos relacionados
Si necesitas proporcionar IDs a varios elementos relacionados, puedes llamar a useId
para generar un prefijo compartido para ellos:
import { useId } from 'react'; export default function Form() { const id = useId(); return ( <form> <label htmlFor={id + '-firstName'}>Nombre:</label> <input id={id + '-firstName'} type="text" /> <hr /> <label htmlFor={id + '-lastName'}>Apellido:</label> <input id={id + '-lastName'} type="text" /> </form> ); }
Esto te permite evitar llamar a useId
para cada elemento que necesite un ID único.
Especificación de un prefijo compartido para todos los IDs generados
Si renderizas varias aplicaciones de React independientes en una sola página, puedes pasar identifierPrefix
como una opción para las llamadas createRoot
o hydrateRoot
. Esto garantiza que los IDs generados por las dos aplicaciones diferentes nunca entren en conflicto porque cada identificador generado con useId
comenzará con el prefijo distinto que hayas especificado.
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 />);
Uso del mismo prefijo de ID en el cliente y el servidor
Si renderizas múltiples aplicaciones de React independientes en la misma página, y algunas de esas aplicaciones son renderizadas en el servidor, asegúrate de que el prefijo identifierPrefix
que le pases a la llamada a hydrateRoot
en el lado del cliente sea el mismo identifierPrefix
que le pases a las APIs del servidor tales como renderToPipeableStream
.
// Server
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' }
);
No necesitas pasar identifierPrefix
si solo tienes una aplicación de React en la página.