Appearance
useId
主要用于生成一个唯一的 ID,这个 ID 在同一个应用中是唯一的,并且在组件更新的时候不会改变。这个功能在处理服务端渲染、列表渲染、表单元素和无障碍属性时非常有用,因为它可以确保每个元素都有一个唯一的标识符。
例子
jsx
function IdComponent() {
const [count, setCount] = React.useState(1);
const vid = React.useId();
const handleChange = () => {
setCount(count + 1);
};
React.useEffect(() => {
setCount(count + 1);
}, []);
return (
<div>
<div> count = {count}</div>
<div> vid = {vid}</div>
<button onClick={handleChange}>修改</button>
</div>
);
}源码阅读
初次渲染
js
/**
* 初次渲染阶段 - 生成组件唯一ID
* @returns
*/
function mountId(): string {
// 获取或者创建一个 hook 对象
const hook = mountWorkInProgressHook();
// 获取根节点
const root = ((getWorkInProgressRoot(): any): FiberRoot);
// 获取用户自定义的 id 前缀字符串
// createRoot(dom , { identifierPrefix : 'myPrefix' })
const identifierPrefix = root.identifierPrefix;
let id;
// 水合状态 创建id
if (getIsHydrating()) {
} else {
// 生成一个 `:r1` 类型的id
// Use a lowercase r prefix for client-generated ids.
const globalClientId = globalClientIdCounter++;
id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":";
}
// 缓存到 hook.memoizedState 上
hook.memoizedState = id;
return id;
}核心就是通过一个 全局变量 globalClientIdCounter的自增去生成应用内唯一的 id,其格式为 :${identifierPrefix}r${id}:, 最后并将生成的值缓存到 hook.memoizedState
更新渲染、更新渲染更新阶段
js
/**
* useId 在更新阶段实现方法
* @returns
*/
function updateId(): string {
// 获取或者创建一个 hook 对象
const hook = updateWorkInProgressHook();
// 直接复用缓存的id
const id: string = hook.memoizedState;
return id;
}核心就是获取缓存到 hook.memoizedState上的 id 的值
使用场景
- 为可访问属性、无障碍属性生成唯一 ID
在表单中,<label> 标签需要通过 for 属性与对应的 <input> 标签的 id 属性相匹配,以实现点击标签时输入框获得焦点的功能。使用 useId 可以为每个 <input> 元素生成一个唯一的 id,确保这一功能的正常工作。例如
jsx
function IdForm() {
const nameId = useId(); // 生成一个 id ':r1:'
return (
<div>
<div>
<label htmlFor={nameId}>用户名称</label>
<input type="text" id={nameId} name="用户名称" />
</div>
</div>
);
}