为了生成唯一的id,React18特地引入了一个新的Hook:useId
时间:2023-03-20 01:20:53
科技观察
大家好,我是Kason。查看以下组件有什么问题://App.tsxconstid=Math.random();exportdefaultfunctionApp(){returnHello
}如果应用是CSR(客户端渲染),id是Stable,App组件没有问题。但是如果应用是SSR(服务端渲染),那么App.tsx会经过:React在服务端渲染生成一个随机id(假设为0.1234),这一步叫做dehydrate(脱水)
Hello 作为HTML传递给客户端,React在客户端渲染为首屏内容生成随机id(假设为0.6789)。此步骤称为水合物(注水)。客户端和服务端生成的id不匹配!事实上,服务端和客户端不能简单的生成一个稳定唯一的id是一个长期存在的问题。早在15年前,就有人提出了这个问题:Generatingrandom/uniqueattributesserver-sidethatdon'tbreakclient-sidemounting[1]直到最近,React18推出了官方Hook——useId,来解决上述问题。他的用法很简单:functionCheckbox(){//生成唯一稳定的idconstid=useId();return(<
DoyoulikeReact?>/>);;用法虽然简单,但背后的原理却很有趣——每个id代表了组件在组件树中的层级结构。这篇文章让我们了解useId的原理。React18来了,一切都变了。虽然这个问题一直存在,但是之前一直可以使用自增的全局count变量作为id。考虑以下示例://GlobalgeneralcountvariableletglobalIdIndex=0;exportdefaultfunctionApp(){constid=useState(()=>globalIdIndex++);returnHello }只要React在服务端和客户端运行在同一个进程中,两端生成的id是对应的。然而,随着ReactFizz(React的新服务器端流式渲染器)的到来,渲染顺序不再是必需的。例如,有一个名为SelectiveHydration的功能,它可以根据用户交互改变水合物的顺序。下图左边部分水合时,用户点击右下部分:React此时会优先水合右下部分:SelectiveHydration更详细的解释见:NewSuspenseSSRArchitectureinReact18[2]如果应用中使用了自增全局count变量作为id,那么显然先水合的组件id会更小,所以id不稳定。那么,有没有在服务器端和客户端都稳定的标记呢?答案是:组件的层次结构。useId的原理假设应用的组件树如下图所示:无论谁先水化B或C,它们的层级结构都保持不变,因此“层级”本身可以作为一个不变的标识在服务器和客户端。比如B可以用2-1作为id,C可以用2-2作为id:functionB(){//idis"2-1"constid=useId();return
B ;}其实有两个要考虑的因素:1、同一个组件使用了多个id,比如这样:functionB(){constid0=useId();constid1=useId();return(