Nota bene

Questa pagina è stata tradotta automaticamente e supervisionata da un maintainer. Un’ulteriore revisione da parte della community sarebbe comunque utile. Migliora questa traduzione.

useId è un Hook React per generare ID univoci che possono essere passati agli attributi di accessibilità.

const id = useId()

Reference

useId()

Chiama useId al top level del tuo componente per generare un ID univoco:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
// ...

Vedi altri esempi sotto.

Parameters

useId non accetta parametri.

Returns

useId restituisce una stringa ID univoca associata a questa particolare chiamata a useId in questo particolare componente.

Caveats

  • useId è un Hook, quindi puoi chiamarlo solo al top level del tuo componente o dei tuoi Hook personalizzati. Non puoi chiamarlo all’interno di loop o condizioni. Se ne hai bisogno, estrai un nuovo componente e sposta lo state al suo interno.

  • useId non dovrebbe essere usato per generare chiavi di cache per use(). L’ID è stabile quando un componente è montato, ma potrebbe cambiare durante la renderizzazione. Le chiavi di cache dovrebbero essere generate dai tuoi dati.

  • useId non dovrebbe essere usato per generare le key in una lista. Le key dovrebbero essere generate dai tuoi dati.

  • useId al momento non può essere usato negli async Server Components.


Usage

Insidia

Non chiamare useId per generare le key in una lista. Le key dovrebbero essere generate dai tuoi dati.

Generare ID univoci per attributi di accessibilità

Chiama useId al top level del tuo componente per generare un ID univoco:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
// ...

Puoi poi passare l’ID generato a diversi attributi:

<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>
</>

Vediamo un esempio per capire quando è utile.

Gli attributi di accessibilità HTML come aria-describedby ti permettono di specificare che due tag sono collegati tra loro. Per esempio, puoi indicare che un elemento (come un input) è descritto da un altro elemento (come un paragrafo).

In HTML classico, lo scriveresti così:

<label>
Password:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
La password deve contenere almeno 18 caratteri
</p>

Tuttavia, hardcodare ID in questo modo non è una buona pratica in React. Un componente può essere renderizzato più volte nella pagina — ma gli ID devono essere univoci! Invece di hardcodare un ID, genera un ID univoco con useId:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Password:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
La password deve contenere almeno 18 caratteri
</p>
</>
);
}

Ora, anche se PasswordField compare più volte sullo schermo, gli ID generati non entreranno in conflitto.

import { useId } from 'react';

function PasswordField() {
  const passwordHintId = useId();
  return (
    <>
      <label>
        Password:
        <input
          type="password"
          aria-describedby={passwordHintId}
        />
      </label>
      <p id={passwordHintId}>
        La password deve contenere almeno 18 caratteri
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Scegli password</h2>
      <PasswordField />
      <h2>Conferma password</h2>
      <PasswordField />
    </>
  );
}

Guarda questo video per vedere la differenza nell’esperienza utente con le tecnologie assistive.

Insidia

Con la renderizzazione lato server useId richiede un albero di componenti identico sul server e sul client. Se gli alberi che renderizzi sul server e sul client non corrispondono esattamente, gli ID generati non corrisponderanno.

Approfondimento

Perché useId è migliore di un contatore incrementale?

Potresti chiederti perché useId è migliore di incrementare una variabile globale come nextId++.

Il vantaggio principale di useId è che React garantisce che funzioni con la renderizzazione lato server. Durante la renderizzazione lato server, i tuoi componenti generano output HTML. In seguito, sul client, l’hydration collega i tuoi gestori di eventi all’HTML generato. Affinché l’hydration funzioni, l’output del client deve corrispondere all’HTML del server.

È molto difficile garantirlo con un contatore incrementale, perché l’ordine in cui i Client Component vengono idratati potrebbe non corrispondere all’ordine in cui l’HTML del server è stato emesso. Chiamando useId, ti assicuri che l’hydration funzioni e che l’output corrisponda tra server e client.

All’interno di React, useId è generato dal “parent path” del componente chiamante. Ecco perché, se l’albero del client e quello del server sono uguali, il “parent path” corrisponderà indipendentemente dall’ordine di renderizzazione.


Se devi assegnare ID a più elementi correlati, puoi chiamare useId per generare un prefisso condiviso per loro:

import { useId } from 'react';

export default function Form() {
  const id = useId();
  return (
    <form>
      <label htmlFor={id + '-firstName'}>Nome:</label>
      <input id={id + '-firstName'} type="text" />
      <hr />
      <label htmlFor={id + '-lastName'}>Cognome:</label>
      <input id={id + '-lastName'} type="text" />
    </form>
  );
}

Questo ti permette di evitare di chiamare useId per ogni singolo elemento che ha bisogno di un ID univoco.


Specificare un prefisso condiviso per tutti gli ID generati

Se renderizzi più applicazioni React indipendenti su una singola pagina, passa identifierPrefix come opzione alle tue chiamate a createRoot o hydrateRoot. Questo garantisce che gli ID generati dalle due app diverse non entrino mai in conflitto, perché ogni identificatore generato con useId inizierà con il prefisso distinto che hai specificato.

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 />);


Usare lo stesso prefisso ID sul client e sul server

Se renderizzi più applicazioni React indipendenti sulla stessa pagina e alcune di queste app sono renderizzate lato server, assicurati che l’identifierPrefix che passi alla chiamata a hydrateRoot sul client sia lo stesso identifierPrefix che passi alle API del server come 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' }
);

Non devi passare identifierPrefix se hai solo un’app React sulla pagina.