Можно ли использовать key вне рендеринга списков в React
Что проверяют
Понимаете ли вы, что key это не атрибут «для map()», а способ сказать React, какой экземпляр компонента перед ним. Отсюда главный практический приём: сброс состояния по ключу. Node.js-разработчику, который пишет и серверный рендер, следом нередко задают вопрос, откуда брать ключи для данных с бэкенда и что будет со случайными ключами при SSR.
Как отвечать
Можно, и это задокументированный приём. При сверке дерева React сравнивает тип элемента и key на одной позиции. Совпали: компонент обновляется с сохранением состояния. Ключ сменился: старый экземпляр размонтируется вместе со своим состоянием и эффектами, а на его месте монтируется новый.
Где это пригождается вне списков:
- сброс формы:
<EditProfile key={userId} />при переходе к другому пользователю очищает всеuseStateвнутри без ручногоuseEffectс обнулением; - неуправляемые поля:
<input defaultValue={draft.text} key={draft.id} />подхватывает новое значение по умолчанию только после смены ключа; - перезапуск анимации или загрузки: смена ключа заново монтирует компонент и запускает его эффекты;
<Fragment key={id}>: когда в списке на один элемент приходится несколько узлов, короткая запись<>ключ принять не может.
В списках ключ должен быть стабильным и уникальным среди соседей, глобальная уникальность не нужна. Лучший источник это идентификатор из базы, который отдаёт ваш API.
Про серверный рендер: ключи в HTML не попадают, но дерево на сервере и на клиенте должно совпадать. Ключ из Math.random() или crypto.randomUUID() прямо в рендере меняется при каждой отрисовке, и компонент будет пересоздаваться постоянно.
Где спотыкаются
Утверждают, что вне списков ключ бесполезен. Интервьюер обычно ждёт именно сброса состояния, это самый частый сценарий.
Пытаются прочитать props.key в дочернем компоненте. Ключ React забирает себе и в пропсы не передаёт, нужное значение передают отдельным пропом.
Ставят индекс массива ключом в списке, который сортируется или из которого удаляют элементы. Состояние и введённый текст «переезжают» к соседним строкам, потому что для React элемент с индексом 2 остался тем же.