5
头图

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).

entanglelane关系, laneAlaneB ,那么某次更新React laneA is selected, then laneB must be included.

That is to say, laneA and laneB are entangled together and die together.

除此之外, laneAlaneClaneClaneB ,那么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 in onChange , the priority is SyncLane
  • updateNum(num + 1) Because it is triggered in startTransition , the priority is one of TransitionLanes

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 than SyncLane 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.


卡颂
3.1k 声望16.7k 粉丝