Hello everyone, I'm Casson.
As a front end, you must be familiar with the concepts of anti-shake ( debounce
) and throttling ( throttle
).
In React18
, based on the new concurrency feature, React
implements the anti-shake function.
Today we are going to talk about how this is achieved.
Welcome to join the human high-quality front-end framework group , with flying
useTransition Demo
useTransition
is a new native Hook
to perform some updates with lower priority .
In our Demo
there are ctn
and num
two states, of which ctn
and the content of the input box are controlled.
When the event of the input box onChange
is triggered, the state changes of ctn
and num
will be triggered at the same time. The method that triggers the num state change (ie updateNum
) is wrapped in startTransition
:
function App() {
const [ctn, updateCtn] = useState('');
const [num, updateNum] = useState(0);
const [isPending, startTransition] = useTransition();
return (
<div >
<input value={ctn} onChange={({target: {value}}) => {
updateCtn(value);
startTransition(() => updateNum(num + 1))
}}/>
<BusyChild num={num}/>
</div>
);
}
num
will be passed as props
to the BusyChild
component. In BusyChild
through while
loop artificially adding components render
The time consumed:
const BusyChild = React.memo(({num}: {num: number}) => {
const cur = performance.now();
// 增加render的耗时
while (performance.now() - cur < 300) {}
return <div>{num}</div>;
})
Therefore, you can obviously feel stuck when entering content in the input box.
Online sample address
It stands to reason that onChange
will trigger the state changes of ctn
and num
at the same time.
However, in fact, after a piece of text is continuously entered in the input box (that is, the state changes of ctn
are continuously displayed in the view), num
will change only once.
As shown in the figure below, the initial input box has no content, num
is 0:
After entering a long text in the input box, num
becomes 1:
This effect is like: the update wrapped by startTransition
has the same anti- shake effect.
How is this achieved?
what is lane
In React18
there is an update priority mechanism , and updates triggered by different places have different priorities. The definition of priority is based on user perception, such as:
- The user does not want the input box to be stuck, so the update triggered in the event
onChange
is the synchronization priority (the highest priority) - The user can accept that there is a waiting time between the request and the return, so the update triggered in
useEffect
is the default priority
So how is the priority expressed? Use a 31-bit binary, called lane
.
For example, the synchronization priority and the default priority are defined as follows:
const SyncLane = 0b0000000000000000000000000000001;
const DefaultLane = 0b0000000000000000000000000010000;
The smaller the value, the higher the priority, namely SyncLane < DefaultLane
.
So React
is to choose one 优先级
--- for each update, and then execute the update corresponding to this priority in all components?
no. If you can only choose one 优先级
per update, then the flexibility is too bad.
So the actual situation is: for each update, React
will select one or more lane
to form a batch, and then perform the update corresponding to the lanes included in this batch in all components
This batch of lane
is called lanes
.
For example, the following code combines SyncLane
with DefaultLane
lanes
:
// 用“按位或”操作合并lane
const lanes = SyncLane | DefaultLane;
entangle mechanism
It can be seen that the lane
mechanism is essentially a variety of bit operations, which can be designed very flexibly.
Based on this, there is a set of mechanisms called entangle
(entanglement).
entangle
指lane
关系, laneA
与laneB
,那么某次更新React
laneA
is selected, then laneB
must be included.
That is to say, laneA
and laneB
are entangled together and die together.
除此之外, laneA
与laneC
, laneC
与laneB
,那么laneA
Also tangled with laneB
.
So what does the entangle
mechanism have to do with useTransition
?
Updates triggered by callbacks wrapped by startTransition
with a priority of one of TransitionLanes
.
TransitionLanes
includes 16 lane
, respectively TransitionLane1
to TransitionLane16
: cd:
And transition相关lane
entanglement occurs.
In our Demo
, every time onChange
is executed, two updates are created:
onChange={({target: {value}}) => {
updateCtn(value);
startTransition(() => updateNum(num + 1))
}
in:
-
updateCtn(value)
Because it is triggered inonChange
, the priority isSyncLane
-
updateNum(num + 1)
Because it is triggered instartTransition
, the priority is one ofTransitionLanes
When entering text repeatedly in the input box, the above process will be repeated, the difference is:
-
SyncLane
Because it is the highest priority, it will be executed, so we will see the content of the input box change -
TransitionLanes相关lane
priority is lower thanSyncLane
will not be executed temporarily, and they will be entangled
In order to prevent an update from being executed due to too low priority, React
has an expiration mechanism : each update has an expiration time. If it is not executed within the expiration time, it will expire. .
Expired updates will be executed synchronously (that is to say, his priority becomes the same as SyncLane
)
In our case, startTransition(() => updateNum(num + 1))
would yield a lot of entangled TransitionLanes相关lane
.
After a period of time, one of them lane
expired, so his priority was raised to the same as SyncLane
and executed immediately.
And since this lane
--- is entangled with the other TransitionLanes相关lane
, they will be executed together.
This is manifested as: the content has been typed in the input box, but num
the number displayed in the view changes after a while.
Summarize
Today we talked about some internal implementations of useTransition
involving:
-
lane
model -
entangle
mechanism - Update expiration mechanism
The most interesting thing is that due to different computer performance, the browser frame rate will change, so in different computers React
will dynamically adjust the anti-shake effect.
This means that you do not need to manually set the time parameters of ---dcbaac7be569361467b4c600afebfc7a debounce
, React
will be dynamically adjusted according to computer performance.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。