useId
useId
je React Hook za generisanje jedinstvenih ID-eva koji se mogu proslediti atributima pristupačnosti.
const id = useId()
Reference
useId()
Pozovite useId
na vrhu vaše komponente da biste generisali jedinstveni ID:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
Parametri
useId
ne prima nikakve parametre.
Povratne vrednosti
useId
vraća jedinstveni ID string asociran za specifični useId
poziv u specifičnoj komponenti.
Upozorenja
-
useId
je Hook, pa ga možete pozvati samo na vrhu vaše komponente ili vaših Hook-ova. Ne možete ga pozvati unutar petlji i uslova. Ako vam je to potrebno, izdvojite novu komponentu i pomerite state u nju. -
useId
ne bi trebao da se koristi za generisanje ključeva u listi. Ključevi trebaju biti generisani na osnovu vaših podataka. -
useId
se trenutno ne može koristiti u asinhronim Server Components.
Upotreba
Generisanje jedinstvenih ID-eva za atribute pristupačnosti
Pozovite useId
na vrhu vaše komponente da biste generisali jedinstveni ID:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
Onda možete proslediti generisani ID u različite atribute:
<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>
</>
Prođimo kroz primer da vidimo kada je ovo korisno.
HTML atributi pristupačnosti kao što je aria-describedby
vam omogućavaju da specificirate dva tag-a koja su povezana. Na primer, možete specificirati da je element (kao što je input) opisan drugim elementom (kao što je paragraph).
U običnom HTML-u napisali biste ovako nešto:
<label>
Šifra:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
Šifra treba da sadrži barem 18 karaktera
</p>
Međutim, hardkodirani ID-evi poput ovih nisu dobra praksa u React-u. Komponenta može biti renderovana više od jednom na stranici—ali ID-evi moraju biti jedinstveni! Umesto da hardkodirate ID, generišite jedinstveni ID sa useId
:
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Šifra:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
Šifra treba da sadrži barem 18 karaktera
</p>
</>
);
}
Sada, čak iako se PasswordField
pojavi više puta na ekranu, generisani ID-evi se neće preklapati.
import { useId } from 'react'; function PasswordField() { const passwordHintId = useId(); return ( <> <label> Šifra: <input type="password" aria-describedby={passwordHintId} /> </label> <p id={passwordHintId}> Šifra treba da sadrži barem 18 karaktera </p> </> ); } export default function App() { return ( <> <h2>Unesi šifru</h2> <PasswordField /> <h2>Potvrdi šifru</h2> <PasswordField /> </> ); }
Pogledajte ovaj video da biste uočili razliku u korisničkom iskustvu sa pomoćnim tehnologijama.
Deep Dive
Možda se pitate zašto je useId
bolji od inkrementiranja globalne promenljive poput nextId++
.
Primarna korist od useId
je da React garantuje da radi sa renderovanjem na serveru. Tokom renderovanja na serveru, vaše komponente generišu HTML izlaz. Kasnije, na klijentu, hidratacijom se povezuju vaši event handler-i sa generisanim HTML-om. Da bi hidratacija radila, klijentski izlaz se mora poklapati sa serverskim HTML-om.
Ovo je teško garantovati sa inkrementalnim brojačem jer se redosled u kom se Client Components hidratizuju možda neće poklapati sa redosledom u kom je emitovan HTML sa servera. Pozivanjem useId
osiguravate da će hidratacija raditi i da će se izlaz servera poklapati sa klijentskim.
Unutar React-a, useId
je generisan na osnovu “roditeljske putanje” pozivajuće komponente. Zbog toga, ako se klijentsko i serversko stablo poklapaju, “roditeljska putanja” će se poklapati bez obzira na redosled.
Generisanje ID-eva za više povezanih elemenata
Ako vam je potrebno da napravite ID-eve za više povezanih elemenata, možete pozvati useId
da generišete deljeni prefiks za njih:
import { useId } from 'react'; export default function Form() { const id = useId(); return ( <form> <label htmlFor={id + '-firstName'}>Ime:</label> <input id={id + '-firstName'} type="text" /> <hr /> <label htmlFor={id + '-lastName'}>Prezime:</label> <input id={id + '-lastName'} type="text" /> </form> ); }
Ovo vam omogućava da izbegnete pozivanje useId
-a za svaki pojedinačni element kojem je potreban jedinstveni ID.
Specificiranje deljenog prefiksa za sve generisane ID-eve
Ako renderujete više nezavisnih React aplikacija na jednog stranici, prosledite identifierPrefix
u vaše createRoot
ili hydrateRoot
pozive. Ovo osigurava da se ID-evi generisani u dve različite aplikacije nikad neće preklapati jer će svaki identifikator generisan sa useId
početi sa različitim prefiksom koji ste specificirali.
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 />);
Upotreba istog ID prefiksa na klijentu i serveru
Ako renderujete više nezavisnih React aplikacija na istoj stranici, a neke od tih aplikacija su renderovane na serveru, postarajte se da identifierPrefix
koji prosleđujete u hydrateRoot
poziv na klijentskoj strani bude isti kao i identifierPrefix
koji prosleđujete u serverske API-je poput renderToPipeableStream
.
// Server
import { renderToPipeableStream } from 'react-dom/server';
const { pipe } = renderToPipeableStream(
<App />,
{ identifierPrefix: 'react-app1' }
);
// Klijent
import { hydrateRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = hydrateRoot(
domNode,
reactNode,
{ identifierPrefix: 'react-app1' }
);
Nije potrebno da prosleđujete identifierPrefix
ako imate samo jednu React aplikaciju na stranici.