在 React 中,useId
是 React 18 引入的一个 Hook,用于生成一个在组件生命周期中保持稳定的唯一 ID。它主要用于:
- 无障碍(accessibility)场景,比如表单控件需要一个
id
和label
的htmlFor
属性配对。 - 服务端渲染(SSR) 与客户端渲染保持一致。
- 避免多个组件生成的 ID 冲突。
🧠 为什么不用自己写 id
?
以前开发者会自己写逻辑生成 id
,比如用 Math.random()
、Date.now()
或 uuid
生成,但这些在服务端渲染(SSR)和客户端渲染中可能不一致,从而导致 水合(hydration)错误。
SSR:服务端渲染出 html 内容,发给浏览器,浏览器接收到 html,先展示静态内容,然后加载动态js,就是将html激活(水合),然后就生成了动态应用,但是这样服务端和浏览器端的 id 生成就会不同(可能随机数生成等等)。
✅ useId
的基本语法
const id = useId();
id
是一个 字符串,React 会自动加前缀,确保唯一性。
🧪 示例:表单中 label 与 input 关联
import React, { useId } from 'react';
function NameInput() {
const id = useId();
return (
<div>
<label htmlFor={id}>姓名:</label>
<input id={id} type="text" />
</div>
);
}
在这个例子中:
label
的htmlFor
和input
的id
使用同一个值。useId()
保证了 ID 在每次渲染中一致,适用于 SSR。
🧩 示例:多个组件实例
function InputField({ label }) {
const id = useId();
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} type="text" />
</div>
);
}
function Form() {
return (
<>
<InputField label="用户名" />
<InputField label="邮箱" />
</>
);
}
每个 InputField
都会生成不同的 id
,即使组件重复使用也不会冲突。
⚠️ 注意事项
useId
不能用在事件处理函数或条件判断内部。- 它不能替代 key、uuid 等复杂 ID 生成需求(比如数据库 ID)。
- 如果你要生成 带后缀的 ID,可以这样做:
const id = useId();
<input id={`${id}-email`} />
🎯 适用场景总结
场景 | 是否推荐用 useId |
---|---|
label 与 input /textarea 等的 ID 配对 | ✅ 是 |
ARIA 属性如 aria-labelledby | ✅ 是 |
SSR 页面保持一致性 | ✅ 是 |
用于生成数据库 ID、URL 等 | ❌ 否 |
如果在使用 React 17 或更低版本,可以用第三方库如 uuid
或 nanoid
作为替代,但在 React 18+ 推荐用 useId
来保证一致性和性能。