Что такое useId в React?

MiddleReact · Frontend·Обновлено 14 августа 2026
Коротко
useId — это хук React 18+, который генерирует уникальный стабильный идентификатор для атрибутов вроде id и aria-*, корректно работающий при серверном рендеринге и гидратации без mismatch-ошибок.

Зачем нужен useId

useId — хук, появившийся в React 18, который генерирует уникальную стабильную строку-идентификатор для использования в атрибутах разметки: id, aria-describedby, aria-labelledby и подобных. Главное отличие от простого счётчика или Math.random() — безопасность при серверном рендеринге (SSR) и последующей гидратации на клиенте.

Проблема, которую решает

До появления useId разработчики генерировали идентификаторы вручную — инкрементным счётчиком, Math.random() или библиотекой uuid. При SSR это приводило к тому, что id, сгенерированный на сервере, не совпадал с id, сгенерированным при повторном рендере на клиенте во время гидратации. React выдавал предупреждения о hydration mismatch, а связка label/input через htmlFor могла сломаться, что критично для доступности (a11y).

useId учитывает позицию компонента в дереве рендеринга, поэтому одно и то же дерево на сервере и клиенте всегда порождает одинаковые id.

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

function Field() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Имя</label>
      <input id={id} type="text" />
    </>
  );
}

Несколько связанных id в одном компоненте

Если внутри компонента нужно несколько разных id, не стоит вызывать useId многократно — правильный подход - вызвать хук один раз и добавлять суффиксы:

function Form() {
  const id = useId();
  return (
    <form>
      <label htmlFor={`${id}-name`}>Имя</label>
      <input id={`${id}-name`} />

      <label htmlFor={`${id}-email`}>Email</label>
      <input id={`${id}-email`} />
    </form>
  );
}

Важные нюансы

  • useId — не замена key. Сгенерированный id не подходит в качестве key для элементов списка: он одинаков для всех экземпляров при одинаковой структуре рендера и не связан с данными элемента.
  • Один вызов на компонент. Хук нельзя вызывать в цикле или условно — это нарушает правила хуков. Для списка полей id формируются суффиксами от одного базового значения либо через компонент-обёртку, вызывающий useId на каждый элемент отдельно.
  • Формат непредсказуем. Возвращаемая строка выглядит как :r0: или :r1: — не стоит полагаться на её вид или пытаться парсить.
  • Несколько React-приложений на странице. Если на одной странице рендерится несколько независимых React-деревьев (несколько вызовов createRoot или renderToString), между ними возможны коллизии id. Для этого у hydrateRoot/createRoot и серверного рендеринга есть опция identifierPrefix, задающая уникальный префикс для каждого дерева.

Когда применять

  • Связка label и input через htmlFor/id.
  • Атрибуты доступности: aria-describedby, aria-labelledby, aria-controls.
  • Любые другие DOM-атрибуты, где нужен уникальный, но детерминированный на сервере и клиенте идентификатор.

Что хочет услышать интервьюер

Понимание, что useId решает проблему hydration mismatch при SSR

Знание, что useId нельзя использовать как key в списках

Пример связки label/htmlFor с useId

Понимание паттерна с суффиксами для нескольких id в одном компоненте

Знание про identifierPrefix для нескольких независимых React-корней на странице

Пример: Базовое использование с label

function Field() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Имя</label>
      <input id={id} type="text" />
    </>
  );
}

Пример: Несколько id в одном компоненте через суффиксы

function Form() {
  const id = useId();

  return (
    <form>
      <label htmlFor={`${id}-name`}>Имя</label>
      <input id={`${id}-name`} />

      <label htmlFor={`${id}-email`}>Email</label>
      <input id={`${id}-email`} type="email" />
    </form>
  );
}

Типичные ошибки

Использование useId для генерации key в map() по списку

Вызов useId в цикле или внутри условия вместо одного вызова на верхнем уровне компонента

Непонимание, зачем вообще нужен useId, если можно использовать Math.random() или uuid

Ожидание, что возвращаемая строка будет коротким читаемым числом, а не служебным форматом вроде :r0:

Незнание про identifierPrefix при работе с несколькими React-приложениями на одной странице

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее