标识与调试 Hooks
如何生成无障碍关联所需的 ID?
- useId: 为组件调用位置生成 ID,适合 label、描述文本与输入的 aria 关系,同一组件可在该 ID 后添加后缀形成一组关联;
- 无条件调用: 在组件或自定义 Hook 顶层调用,不能为了只在某分支显示输入而条件调用;
- 非数据身份: 不用 useId 生成列表 key 或 use 的资源缓存 key,这些身份必须来自数据,不能依赖尚未挂载时可能变化的组件 ID;
import { useId } from "react";
function PasswordField() {
const id = useId();
return (
<>
<label htmlFor={id}>密码</label>
<input id={id} type="password" aria-describedby={id + "-hint"} />
<p id={id + "-hint"}>请使用足够长的密码。</p>
</>
);
}
服务端渲染与多个 root 如何保持 ID 一致?
- 树一致: useId 支持服务端与客户端相同树结构下的匹配,不能补救两端渲染结构不同;
- 根前缀: 多个独立 root 可用 identifierPrefix 避免冲突,服务端与 hydrateRoot 必须使用一致前缀;
- 调用限制: 当前不能在 async Server Components 中调用 useId,需要在适当组件边界生成标识;
如何让自定义 Hook 在 DevTools 中更易读?
- useDebugValue: 给 React DevTools 中的自定义 Hook 添加可读标签,不会把调试值渲染到页面;
- 按需使用: 复杂、共享的 Hook 适合标注,不必给每个简单 Hook 添加额外标签;
- 延迟格式化: 第二参数是 formatter,只在检查 Hook 时格式化,避免每次渲染进行昂贵调试计算;
import { useDebugValue } from "react";
function useNamedDebugValue(value) {
useDebugValue(value, (current) => `当前值:${current}`);
return value;
}
ID 与调试值能否承担业务状态?
- 明确用途: useId 解决可访问性关联,useDebugValue 解决工具展示,两者都不替代数据库 ID 或可更新的业务 state;