简介
useId是新增的用于生成惟一ID值的hook钩子,次要用于客户端和服务器端应用,同时防止 dehydrate 过程中数据不匹配的问题。
它次要用于与须要惟一 ID 的可拜访性 API 集成的组件库。这解决了 React 17 及更低版本中曾经存在的问题,但在 React 18 中更为重要,因为新的流式服务器渲染器如何无序交付 HTML。
然而,不倡议用于List中作为key应用,列表中的惟一key应该应用List中的数据。
问题
React渲染有客户端渲染(CSR)和服务端渲染(SSR)。
假如有如下代码片段:
// App.tsxconst id = Math.random();export default function App() { return <div id={id}>Hello</div>}
如果利用是CSR(客户端渲染),id是稳固的,App组件没有问题。
但如果利用是SSR(服务端渲染),那么App.tsx会分为以下几步:
- React在服务端渲染,生成随机id(假如为0.1234),这一步叫dehydrate(脱水);
- <div id="0.12345">Hello</div>作为HTML传递给客户端,作为首屏内容;
- React在客户端渲染,生成随机id(假如为0.6789),这一步叫hydrate(注水)。
客户端、服务端生成的id不匹配!
原始解决形式:
// 全局通用的计数变量let globalIdIndex = 0;export default function App() { const id = useState(() => globalIdIndex++); return <div id={id}>Hello</div>}
只有React在服务端、客户端的运行流程统一,那么双端产生的id就是对应的。
然而,随着React Fizz(React新的服务端流式渲染器)的到来,渲染程序不再肯定。
比方,有个个性叫 Selective Hydration,能够依据用户交互扭转hydrate的程序。
当下图左侧局部在hydrate时,用户点击了右下角局部:
此时React会优先对右下角局部hydrate:
因而,自增的全局计数变量作为id,不再精确!!
那么,有没有什么是服务端、客户端都稳固的标记呢?
答案是:组件的层次结构。
useId的原理
假如利用的组件树如下图:
不论B和C谁先hydrate,他们的层级构造是不变的,所以「层级」自身就能作为服务端、客户端之间不变的标识。
比方B能够应用2-1作为id,C应用2-2作为id:
function B() { // id为"2-1" const id = useId(); return <div id={id}>B</div>;}
如何在一个组件中应用多个useId()?
react举荐应用雷同的id+后缀:
function NameFields() { const id = useId(); return ( <div> <label htmlFor={id + '-firstName'}>First Name</label> <div> <input id={id + '-firstName'} type="text" /> </div> <label htmlFor={id + '-lastName'}>Last Name</label> <div> <input id={id + '-lastName'} type="text" /> </div> </div> );}