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
-
useIdje 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. -
useIdne bi trebao da se koristi za generisanje ključeva u listi. Ključevi trebaju biti generisani na osnovu vaših podataka. -
useIdse 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.