当前位置: 首页 > Web前端 > HTML

为了生成唯一的id,React18特地引入了一个新的Hook:useId

时间:2023-03-28 14:38:46 HTML

大家好,我是Kason。看看下面这个组件有什么问题://App.tsxconstid=Math.random();exportdefaultfunctionApp(){returnHello

}如果应用是CSR(客户端渲染),id稳定,App组件没有问题。但是如果应用是SSR(服务端渲染),那么App.tsx会经过:React在服务端渲染生成一个随机id(假设为0.1234),这一步叫做dehydrate(脱水)Hello
作为HTML传递给客户端,React将其渲染在客户端作为首屏内容生成一个随机id(假设为0.6789)。此步骤称为水合物(注水)。客户端和服务器生成的id不匹配!实际上,服务端和客户端不能简单的生成一个稳定唯一的id是一个长期存在的问题。早在15年前,就有人提出了这个问题:Generatingrandom/uniqueattributesserver-sidethatdon'tbreakclient-sidemounting直到最近,React18推出了官方的Hook——useId,来解决上述问题。他的用法很简单:functionCheckbox(){//生成唯一稳定的idconstid=useId();return(<>你喜欢React吗?);;用法虽然简单,但背后的原理却很有趣——每个id代表了组件在组件树中的层级结构。这篇文章让我们了解useId的原理。欢迎加入人类优质前端框架群。随着React18的到来,一切都变了。虽然这个问题一直存在,但是一直可以用自增的全局计数变量作为id。考虑以下示例://globalcommoncountingvariableletglobalIdIndex=0;exportdefaultfunctionApp(){constid=useState(()=>globalIdIndex++);returnHello
}只要React在服务端和客户端运行在同一个进程,那么双端生成的id就是对应的。然而,随着ReactFizz(React的新服务器端流式渲染器)的到来,渲染顺序不再是必需的。例如,有一个名为SelectiveHydration的功能,它可以根据用户交互改变水合物的顺序。下图左边部分水合时,用户点击右下部分:React此时会优先水合右下部分:SelectiveHydration更详细的解释见:NewSuspenseSSRArchitectureinReact18如果应用使用自增全局count变量作为id,那么显然先水合的组件id会更小,所以id不稳定。那么,有没有迹象表明服务器和客户端都稳定了呢?答案是:组件的层次结构。useId的原理假设应用的组件树如下图所示:无论谁先水化B或C,它们的层级结构都保持不变,因此层级本身可以作为服务端和服务端之间的不变标识客户端。例如,B可以使用2-1作为id,C可以使用2-2作为id:functionB(){//idis"2-1"constid=useId();returnB
;}其实需要考虑两个要素:1.同一个组件使用多个id像这样:functionB(){constid0=useId();constid1=useId();return();}2.跳过不使用useId的组件,考虑这个组件树形结构:如果组件A、D使用了useId,而B、C没有使用,那么只需要为A、D定义层级即可,可以减少表达层级的需要。在useId的实际实现中,级别表示为base-32数字。之所以选择32为基数,是因为选择尽可能大的基数会使生成的字符串尽可能紧凑。例如:consta=18;//"10010"length5a.toString(2)//"i"length1a.toString(32)具体的useId级别算法,参考useId总结。React源码内部有各种栈结构(比如在栈上使用,用于保存上下文数据)。useId堆栈的逻辑是比较复杂的逻辑之一。谁能想到这么简单的API背后,实现起来却如此复杂?React团队修补并发特性并不容易......

最新推荐
猜你喜欢