useId

useId — хук React для генерацыі ўнікальных ідэнтыфікатараў, якія далей можна выкарыстоўваць у атрыбутах даступнасці.

const id = useId()

Апісанне

useId()

Выклічце useId на верхнім узроўні вашага кампанента, каб згенераваць унікальны ідэнтыфікатар:

import { useId } from 'react';

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

Болей прыкладаў глядзіце ніжэй.

Параметры

useId не прымае аніякіх параметраў.

Значэнні, якія вяртаюцца

useId вяртае радок з унікальным ідэнтыфікатарам, які звязаны з гэтым канкрэтным выклікам useId у гэтым канкрэтным кампаненце.

Агаворкі

  • useId — хук, а значыць, вы можаце выклікаць яго толькі на верхнім узроўні вашага кампанента ці ўнутры ўласнага хука. Ëн не можа быць выкліканы ўнутры цыкла альбо ўмовы. Калі вам усё ж гэта патрэбна, то стварыце новы кампанент і перанясіце стан туды.
  • useId не мусіць выкарыстоўвацца для генерацыі ключоў кэша для use(). Ідэнтыфікатар стабільны пры манціраванні, але можа змяняцца паміж рэндарамі. Ключы кэша мусяць генерыравацца на падставе вашых даных.
  • useId не мусіць выкарыстоўвацца для генерацыі ключоў у спісах. Ключы мусяць генерыравацца на падставе вашых даных.
  • useId на дадзены момант не можа быць выкарыстаны ўнутры асінхронных серверных кампанентаў.

Выкарыстанне

Pitfall

Не выкарыстоўвайце useId для генерацыі ключоў у спісах. Ключы мусяць генерыравацца на падставе вашых даных.

Генерацыя ўнікальных ідэнтыфікатараў для атрыбутаў даступнасці

Выклічце useId на верхнім узроўні вашага кампанента каб згенераваць унікальны ідэнтыфікатар:

import { useId } from 'react';

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

Далей вы можаце перадаць згенераваны ідэнтыфікатар у розныя атрыбуты:

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

Давайце разгледзім прыклад, калі гэта можа быць карысна.

Атрыбуты даступнасці ў HTML як, напрыклад, aria-describedby дазваляюць пазначыць, што два тэгі звязаныя адзін з адным. Такім чынам, як варыянт, вы можаце адзначыць, што элемент (напрыклад, поле ўводу) апісаны іншым элементам (напрыклад, параграфам).

У звычайным HTML, вы б апісалі гэта так:

<label>
Пароль:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
Пароль мусіць змяшчаць як мінімум 18 сімвалаў
</p>

Але ўказанне ідэнтыфікатара наўпрост у кодзе не з’яўляецца добрай практыкай у React. На старонцы кампанент можа быць адрэндараны болей за адзін раз, а ідэнтыфікатары павінны быць унікальнымі! Замест указання пастаяннага ідэнтыфікатара, згенеруйце ўнікальны з дапамогай useId:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Пароль:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
Пароль мусіць змяшчаць як мінімум 18 сімвалаў
</p>
</>
);
}

Цяпер, нават калі PasswordField з’явіцца на старонцы некалькі разоў, згенераваныя ідэнтыфікатары не будуць канфліктаваць.

import { useId } from 'react';

function PasswordField() {
  const passwordHintId = useId();
  return (
    <>
      <label>
        Пароль:
        <input
          type="password"
          aria-describedby={passwordHintId}
        />
      </label>
      <p id={passwordHintId}>
        Пароль мусіць змяшчаць як мінімум 18 сімвалаў
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Прыдумайце пароль</h2>
      <PasswordField />
      <h2>Пацвердзіце пароль</h2>
      <PasswordField />
    </>
  );
}

Азнаёмцеся з відэа, каб убачыць розніцу ў карыстальніцкім досведзе пры выкарыстанні дапаможных тэхналогій.

Pitfall

Пры серверным рэндарынгу, useId патрабуе ідэнтычнага дрэва кампанентаў на серверы і на кліенце. Калі дрэвы, што вы рэндарыце на кліенце і серверы не супадаюць, згенераваныя ідэнтыфікатары будуць адрознымі.

Deep Dive

Чаму useId лепей за інкрэментальны лічыльнік?

Вы можаце задумацца: чаму useId лепей за інкрэментальную глабальную пераменную накшталт nextId++.

Асноўная перавага useId у тым, што React забяспечвае працу пры серверным рэндарынгу. Падчас сервернага рэндарынгу, з вашых кампанентаў генеруецца HTML. Потым, на кліенце, падчас гідратацыі адбываецца прывязка апрацоўшчыкаў падзей да згенераванага HTML. Каб гідратацыя спрацавала, вынік кліента мусіць супадаць з HTML сервера.

Гэта вельмі цяжка гарантаваць праз інкрэментальны лічыльнік, бо парадак, у якім кліент робіць гідратацыю кампанентаў, можа не адпавядаць парадку, у якім сервер складае HTML. Карыстаючыся useId, можна гарантаваць, што гідрадацыя спрацуе, і вынік будзе аднолькавым і на серверы, і кліенце.

Унутры React, useId генеруецца на падставе размяшчэння бацькоўскага кампанента». Менавіта таму, калі дрэвы кліента і сервера ідэнтычныя, «размяшчэнне бацькоўскага кампанента» будзе супадаць незалежна ад парадку рэндара.


Калі вам трэба даць ідэнтыфікатары некалькім звязаным элементам, вы можаце выкарыстаць useId каб згенераваць агульны прэфікс для іх:

import { useId } from 'react';

export default function Form() {
  const id = useId();
  return (
    <form>
      <label htmlFor={id + '-firstName'}>Імя:</label>
      <input id={id + '-firstName'} type="text" />
      <hr />
      <label htmlFor={id + '-lastName'}>Прозвішча:</label>
      <input id={id + '-lastName'} type="text" />
    </form>
  );
}

Гэта дазволіць вам пазбегнуць выклікаў useId для кожнага элемента, які патрабуе ўнікальны ідэнтыфікатар.


Вызначэнне агульнага прэфікса для ўсіх згенераваных ідэнтыфікатараў

Калі вы рэндарыце некалькі незалежных праграм React на адной старонцы, перадайце identifierPrefix у опцыях да вашых выклікаў createRoot ці hydrateRoot. Гэта гарантуе, што ідэнтыфікатары з дзвюх розных праграм не будуць канфліктаваць, бо кожны згенераваны праз useId ідэнтыфікатар будзе пачынацца з адрознага прэфікса, які вы ўказалі.

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


Выкарыстанне аднолькавых прэфіксаў для ідэнтыфікатараў на кліенце і на серверы

Калі вы рэндарыце некалькі незалежных праграм React на адной старонцы, і некаторыя з гэтых праграм рэндарацца на серверы, пераканайцеся, што identifierPrefix, які вы перадаяце ў выклік hydrateRoot на кліенце, ідэнтычны identifierPrefix, які вы перадаяце праз API сервера, такія як 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' }
);

У identifierPrefix няма патрэбы, калі вы маеце толькі адну праграму React на старонцы.