Hi everyone, I'm Kasong.
See what is wrong with the following components:
// App.tsx
const id = Math.random();
export default function App() {
return <div id={id}>Hello</div>
}
If the application is CSR
(client rendering), id
is stable, and there is no problem App
But if the application is SSR
(server rendering), then App.tsx
will experience:
React
is rendered on the server side to generate randomid
(assuming0.1234
), this step is calleddehydrate
(dehydration)<div id="0.12345">Hello</div>
passed to the client asHTML
as the first screen contentReact
is rendered on the client and generates randomid
(assuming0.6789
), this step is calledhydrate
(water injection)
id
generated by the client and server do not match!
In fact, the fact that the server and client cannot simply generate a stable and unique id
is a long-standing problem. As early as 15 years, someone mentioned issue
:
Generating random/unique attributes server-side that don't break client-side mounting
Until recently, React18
launched the official Hook
—— useId
to solve the above problems. His usage is very simple:
function Checkbox() {
// 生成唯一、稳定id
const id = useId();
return (
<>
<label htmlFor={id}>Do you like React?</label>
<input type="checkbox" name="react" id={id} />
</>
);
);
Although the usage is simple, the principle behind it is very interesting-each id
represents the hierarchical structure of the component in the component tree.
This article lets us understand the principle of useId
Welcome to join human high-quality front-end frame group , take flight
React18 is here, everything has changed
Although this problem has always existed, the global count variable of auto-increment can be used as
id
. Consider the following example:
// 全局通用的计数变量
let globalIdIndex = 0;
export default function App() {
const id = useState(() => globalIdIndex++);
return <div id={id}>Hello</div>
}
As long as React
on the server side and the client side is consistent, then the id
produced by both ends corresponds.
However, with the React Fizz
( React
new server-side streaming renderer), the rendering order is no longer certain.
For example, there is a feature called Selective Hydration
, the user can interactively change the hydrate
order.
When the left part of the hydrate
is at 061a4c7d7baf34, the user clicks on the lower right part:
At this time, React
will give priority to the lower right part hydrate
:
Selective Hydration
more detailed explanation of see: 161a4c7d7bafb0 New Suspense SSR Architecture in React 18
If the application uses the auto-incremented global count variable as
id
, then obviously the first hydrate
component id
will be smaller, so id
is unstable.
So, is there a stable mark for both the server and the client?
The answer is: the hierarchy of components.
The principle of useId
Suppose the component tree of the application is as follows:
Regardless of whether B
or C
first hydrate
, their hierarchical structure is the same, so the level itself can be used as a constant identifier between the server and the client.
For example, B
can use 2-1
as id
, and C
use 2-2
as id
:
function B() {
// id为"2-1"
const id = useId();
return <div id={id}>B</div>;
}
There are actually two elements that need to be considered:
1. Use multiple IDs for the same component
For example:
function B() {
const id0 = useId();
const id1 = useId();
return (
<ul>
<li id={id0}></li>
<li id={id1}></li>
</ul>
);
}
2. To skip components that do not use useId
Still consider this component tree structure:
If the component A
, D
used useId
, B
, C
not used, then you only need to A
, D
delineated hierarchy, so that we can reduce the need to represent the hierarchy .
In useId
, the level is expressed as a 32-ary number.
The reason for choosing 32 hexadecimal is because choosing the largest possible hexadecimal will make the generated string as compact as possible. for example:
const a = 18;
// "10010" length 5
a.toString(2)
// "i" length 1
a.toString(32)
For the specific useId
level algorithm useId
Summarize
React
source code has a variety of stack structures (such as the
stack
context
data).
useId
stack is one of the more complicated ones.
Who would have thought API
, which is so simple to use, is so complicated?
React
team with the , which is really not easy...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。