Spec-Zone.ru › React 18

useId

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

const id = useId()
  • Справочник
    • useId()
  • Использование
    • Генерация уникальных идентификаторов для атрибутов доступности
    • Генерация идентификаторов для нескольких связанных элементов
    • Указание общего префикса для всех сгенерированных идентификаторов
    • Использование одного префикса идентификатора на клиенте и сервере

Справочник

useId()

Вызовите useId на верхнем уровне вашего компонента, чтобы сгенерировать уникальный идентификатор:

import { useId } from 'react';

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

См. дополнительные примеры ниже.

Параметры

useId не принимает никаких параметров.

Возвращаемое значение

useId возвращает строку с уникальным идентификатором, связанным с этим конкретным вызовом useId в этом конкретном компоненте.

Ограничения

  • useId — это хук, поэтому вы можете вызывать его только на верхнем уровне вашего компонента или собственных хуков. Вы не можете вызывать его внутри циклов или условий. Если вам это нужно, создайте новый компонент и перенесите в него состояние.

  • useId не следует использовать для генерации ключей в списке. Ключи должны генерироваться из ваших данных.


Использование

Опасность

Не вызывайте 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>
  Password:
  <input
    type="password"
    aria-describedby="password-hint"
  />
</label>
<p id="password-hint">
  The password should contain at least 18 characters
</p>

Однако жёсткая кодировка идентификаторов, подобная этой, не является хорошей практикой в React. Компонент может быть рендеризирован более одного раза на странице — но идентификаторы должны быть уникальными! Вместо жёсткой кодировки идентификатора сгенерируйте уникальный идентификатор с помощью 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>
    </>
  );
}

Теперь, даже если PasswordField появляется на экране несколько раз, сгенерированные идентификаторы не будут конфликтовать.

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

Посмотрите это видео, чтобы увидеть разницу в пользовательском опыте с помощью вспомогательных технологий.

Опасность

При рендеринге на сервере, useId требует идентичного дерева компонентов на сервере и клиенте. Если деревья, которые вы рендерите на сервере и клиенте, не совпадают точно, сгенерированные идентификаторы не будут совпадать.

Подробное рассмотрение

Почему 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'}>First Name:</label>
      <input id={id + '-firstName'} type="text" />
      <hr />
      <label htmlFor={id + '-lastName'}>Last Name:</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-приложение на странице.

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://18.react.dev/reference/react/useId

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API