gpt4 book ai didi

为了生成唯一id,React18专门引入了新Hook:useId

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 24 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章为了生成唯一id,React18专门引入了新Hook:useId由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

为了生成唯一id,React18专门引入了新Hook:useId

大家好,我卡颂.

看看如下组件有什么问题:

  1. // App.tsx
  2. const id = Math.random();
  3. export default function App() {
  4. return
    Hello
  5. }

如果应用是CSR(客户端渲染),id是稳定的,App组件没有问题.

但如果应用是SSR(服务端渲染),那么App.tsx会经历:

  1. React在服务端渲染,生成随机id(假设为0.1234),这一步叫dehydrate(脱水)
  2. Hello
    作为HTML传递给客户端,作为首屏内容
  3. React在客户端渲染,生成随机id(假设为0.6789),这一步叫hydrate(注水)

客户端、服务端生成的id不匹配.

事实上,服务端、客户端无法简单生成稳定、唯一的id是个由来已久的问题,早在15年就有人提过issue:

Generating random/unique attributes server-side that don't break client-side mounting[1] 。

直到最近,React18推出了官方Hook——useId,才解决以上问题。他的用法很简单:

  1. function Checkbox() {
  2. // 生成唯1、稳定id
  3. const id = useId();
  4. return (
  5. <>
  6. "checkbox" name="react" id={id} />
  7. );
  8. );

虽然用法简单,但背后的原理却很有意思 —— 每个id代表该组件在组件树中的层级结构.

本文让我们来了解useId的原理.

React18来了,一切都变了

这个问题虽然一直存在,但之前一直可以使用自增的全局计数变量作为id,考虑如下例子:

  1. // 全局通用的计数变量
  2. let globalIdIndex = 0;
  3. export default function App() {
  4. const id = useState(() => globalIdIndex++);
  5. return
    Hello
  6. }

只要React在服务端、客户端的运行流程一致,那么双端产生的id就是对应的.

但是,随着React Fizz(React新的服务端流式渲染器)的到来,渲染顺序不再一定.

比如,有个特性叫 Selective Hydration,可以根据用户交互改变hydrate的顺序.

当下图左侧部分在hydrate时,用户点击了右下角部分:

为了生成唯一id,React18专门引入了新Hook:useId

此时React会优先对右下角部分hydrate:

为了生成唯一id,React18专门引入了新Hook:useId

关于Selective Hydration更详细的解释见:New Suspense SSR Architecture in React 18[2] 。

如果应用中使用自增的全局计数变量作为id,那么显然先hydrate的组件id会更小,所以id是不稳定的.

那么,有没有什么是服务端、客户端都稳定的标记呢?

答案是:组件的层次结构.

useId的原理

假设应用的组件树如下图:

为了生成唯一id,React18专门引入了新Hook:useId

不管B和C谁先hydrate,他们的层级结构是不变的,所以「层级」本身就能作为服务端、客户端之间不变的标识.

比如B可以使用2-1作为id,C使用2-2作为id:

  1. function B() {
  2. // id为"2-1"
  3. const id = useId();
  4. return
    B
    ;
  5. }

实际需要考虑两个要素:

1. 同一个组件使用多个id

比如这样:

  1. function B() {
  2. const id0 = useId();
  3. const id1 = useId();
  4. return (
  5. );
  6. }

2. 要跳过没有使用useId的组件

还是考虑这个组件树结构:

为了生成唯一id,React18专门引入了新Hook:useId

如果组件A、D使用了useId,B、C没有使用,那么只需要为A、D划定层级,这样就能「减少需要表示层级」.

在useId的实际实现中,层级被表示为「32进制」的数.

之所以选择「32进制」,是因为选择尽可能大的进制会让生成的字符串尽可能紧凑。比如:

  1. const a = 18;
  2. // "10010" length 5
  3. a.toString(2)
  4. // "i" length 1
  5. a.toString(32)

具体的useId层级算法参考useId[3] 。

总结

React源码内部有多种栈结构(比如用于保存context数据的栈).

useId 栈的逻辑是其中比较复杂的一种.

谁能想到用法如此简单的API背后,实现起来居然这么复杂?

React团队捣鼓「并发特性」,真挺不容易的... 。

参考资料

[1]Generating random/unique attributes server-side that don't break client-side mounting

https://github.com/facebook/react/issues/4000 。

[2]New Suspense SSR Architecture in React 18

https://github.com/reactwg/react-18/discussions/37 。

[3]useId

https://github.com/facebook/react/pull/22644 。

原文链接:https://mp.weixin.qq.com/s/Ghnjq9JLHOCUNPFANEfG3Q 。

最后此篇关于为了生成唯一id,React18专门引入了新Hook:useId的文章就讲到这里了,如果你想了解更多关于为了生成唯一id,React18专门引入了新Hook:useId的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com