React中的useId

简介

useId是新增的用于生成唯一ID值的hook钩子,主要用于客户端和服务器端使用,同时避免 dehydrate 过程中数据不匹配的问题。

它主要用于与需要唯一 ID 的可访问性 API 集成的组件库。这解决了 React 17 及更低版本中已经存在的问题,但在 React 18 中更为重要,因为新的流式服务器渲染器如何无序交付 HTML。

但是,不建议用于List中作为key使用,列表中的唯一key应该使用List中的数据。

问题

React渲染有客户端渲染(CSR)和服务端渲染(SSR)。

假设有如下代码片段:

// App.tsx
const id = Math.random();

export default function App() {
  return 
Hello
}

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

但如果应用是SSR(服务端渲染),那么App.tsx会分为以下几步:

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

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

原始解决方式:

// 全局通用的计数变量
let globalIdIndex = 0;


export default function App() {
  const id = useState(() => globalIdIndex++);
  return 
Hello
}

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

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

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

当下图左侧部分在hydrate时,用户点击了右下角部分:
React中的useId_第1张图片
此时React会优先对右下角部分hydrate:
React中的useId_第2张图片

因此,自增的全局计数变量作为id,不再准确!!

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

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

useId的原理

假设应用的组件树如下图:
React中的useId_第3张图片
不管B和C谁先hydrate,他们的层级结构是不变的,所以「层级」本身就能作为服务端、客户端之间不变的标识。

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

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

如何在一个组件中使用多个useId()?
react推荐使用相同的id+后缀:

function NameFields() {
  const id = useId();
  return (
    
); }

你可能感兴趣的:(react.js前端)