用来拿到一个 id 字符串,传递给 a11y 的属性。
这个 id 不应该被当做列表渲染的 key,我们应该用自己的数据生成 key。
用法
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>
</>
);
}
HTML 有很多 a11y 的属性,用来表示两个标签是有关联性的,可能会被类似于 screen reader 的东东利用好。比如我们可以指定一个标签被另一个标签描述了:
<label>
Password:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
The password should contain at least 18 characters
</p>
但是这样写死代码会带来问题,比如如果这段代码被抽成组件在一个页面上复用多次的话,id 就重复了——但它不应该重复,所以 useId 就派上用场了。
为什么不用自增 id?
最重要的好处就是 react 会保证在 SSR 的场景下也会有效。在 SSR 中,组件产生 HTML 输出,然后再客户端 hydration 过程会把事件 handler 绑定到 DOM 上。为了保证 hydration 的正确执行,客户端和服务端的 HTML 必须匹配。
自增 id 在这方面很难保证,因为客户端组件进行 hydration 的顺序可能不会跟在服务端输出 HTML 的顺序一致,从而可能导致不一样的 id。但是用 useId 可以保证获取到一样的 id。
在 react 内部,useId 是根据 parent path 来生成的,所以只要服务端和客户端的组件树结构一样的话,就能得到相同的 id。
多 React App 场景
在一个页面下要渲染多个 React App 的场景下,我们还可以为 id 加上以 App 为颗粒度的 id 前缀,用来区分多个 App,详情可以去 react.dev/reference/r… 看看更细的用法。