Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How does useState execute the process?

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces "how the useState execution process makes". In the daily operation, I believe many people have doubts about what the useState implementation process makes. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "how the useState implementation process makes". Next, please follow the editor to study!

As a React developer, can you answer the following two questions:

For the following function components:

Function App () {const [num, updateNum] = useState (0); window.updateNum = updateNum; return num;}

Can the 0 in the view be updated to 1 by calling window.updateNum (1)?

For the following function components:

Function App () {const [num, updateNum] = useState (0); function increment () {setTimeout (()) = > {updateNum (num + 1);}, 1000);} return {num}

;}

Quickly click p5 times in 1 second, how many times does it show on the view?

1. Yes, 2. Show as 1

In fact, these two questions are essentially asking:

How does useState save state?

How does useState update status?

This article will be combined with the source code to explain the above two questions.

That's all you need to know about useState.

How hook saves data

FunctionComponent's render itself is just a function call.

So how does the hook called inside render get the corresponding data?

For example:

UseState gets state

UseRef gets ref

UseMemo acquires cached data

The answer is:

Each component has a corresponding fiber node (which can be understood as a virtual DOM), which is used to hold information about the component.

Each time you FunctionComponent render, the global variable currentlyRenderingFiber is assigned to the fiber node corresponding to that FunctionComponent.

So, inside hook, you actually get status information from currentlyRenderingFiber.

How to get data from multiple hook

We know that there may be multiple hook in a FunctionComponent, such as:

Function App () {/ / hookA const [a, updateA] = useState (0); / / hookB const [b, updateB] = useState (0); / / hookC const ref = useRef (0); return

;}

So how do multiple hook get their own data?

The answer is:

An one-way linked list of data corresponding to hook is kept in currentlyRenderingFiber.memoizedState.

For the example above, it can be understood as:

Const hookA = {/ / hook saved data memoizedState: null, / / points to the next hook next: hookB / /. Omit other fields}; hookB.next = hookC;currentlyRenderingFiber.memoizedState = hookA

When FunctionComponent render, each time a hook is executed, the pointer to the currentlyRenderingFiber.memoizedState linked list is moved backwards to the current hook corresponding data.

This is why React requires that the order of hook calls cannot be changed (hook cannot be used in conditional statements)-each time render is fetched from a fixed-order linked list.

UseState execution process

We know that the second parameter of the useState return value array is the method that changes the state.

In the source code, he is called dispatchAction.

Whenever dispatchAction is called, an object update representing an update is created:

Const update = {/ / updated data action: action, / / points to the next update next: null}

For the following example

Function App () {const [num, updateNum] = useState (0); function increment () {updateNum (num + 1);} return {num}

;}

Calling updateNum (num + 1) creates:

Const update = {/ / updated data action: 1, / / points to the next update next: null / /. Omit other fields}

If you call dispatchAction multiple times, for example:

Function increment () {/ / generate update1 updateNum (num + 1); / generate update2 updateNum (num + 2); / / generate update3 updateNum (num + 3);}

Then the update forms a circular linked list.

Update3-- next-- > update1 ^ | | update2 | _ next_ |

Where can I keep this linked list?

Since the update linked list is generated by the dispatchAction of a useState, the linked list clearly belongs to that useState hook.

We continue to supplement the data structure of hook.

Const hook = {/ / hook saved data memoizedState: null, / / points to the next hook next: hookForB / / this update calculates the new state baseState: null based on baseState, / / the update queue that already existed at the beginning of this update baseQueue: null, / / the update queue to be added for this update queue: null,}

Among them, the linked list of the updated update is saved in queue.

When calculating state, the circular linked list of queue is cut and mounted at the end of baseQueue, and baseQueue calculates the new state based on baseState.

After calculating the state, the new state becomes memoizedState.

The reason why updates are not based on memoizedState but on baseState is that priority needs to be considered in the calculation process of state, and some update priorities may not be skipped. So memoizedState is not necessarily the same as baseState.

Let's go back to our first question at the beginning:

Function App () {const [num, updateNum] = useState (0); window.updateNum = updateNum; return num;}

Can the 0 in the view be updated to 1 by calling window.updateNum (1)?

We need to look at the concrete implementation of the updateNum method here:

UpdateNum = = dispatchAction.bind (null, currentlyRenderingFiber, queue)

As you can see, the updateNum method binds the dispatchAction of currentlyRenderingFiber and queue (that is, hook.queue).

As mentioned earlier, the purpose of calling dispatchAction is to generate update and insert it into the hook.queue linked list.

Now that queue has been bound to dispatchAction as a preset parameter, calling dispatchAction is limited to FunctionComponent.

Action of update

The second question

Function App () {const [num, updateNum] = useState (0); function increment () {setTimeout (()) = > {updateNum (num + 1);}, 1000);} return {num}

;}

Quickly click p5 times in 1 second, how many times does it show on the view?

We know that calling updateNum produces update, where passing parameters becomes update.action.

Click 5 times in 1 second. At the fifth click, the update created by the first click has not yet entered the update process, so the hook.baseState has not changed.

Then the update generated by these five clicks is based on the same baseState to calculate the new state, and the num variable has not changed (that is, five times update.action (that is, num + 1) is the same value).

Therefore, the final rendering result is 1.

UseState and useReducer

So, how do you gradually change the view from 1 to 5 with 5 clicks?

From the above knowledge, we know that we need to change baseState or action.

BaseState is determined by the update process of React, and we can't control it.

But we can control action.

Action can pass not only values but also functions.

/ / action is updateNum (num + 1); / / action is function updateNum (num = > num + 1)

In the process of generating a new state based on baseState and update linked lists:

Let newState = baseState;let firstUpdate = hook.baseQueue.next;let update = firstUpdate;// traverses every updatedo {if (typeof update.action = 'function') {newState = update.action (newState) in baseQueue;} else {newState = action;}} while (update! = = firstUpdate)

It can be seen that when passing a value, since our action is the same value five times, the final calculated newState is also the same value.

In the case of transfer function, newState calculates 5 times based on action function, and finally gets the cumulative result.

If we use useReducer instead of useState in this example, since the action of useReducer is always a function, we won't encounter the problem in our example.

In fact, useState itself is a useReducer with the following reducer preset.

Function basicStateReducer (state, action) {return typeof action = = 'function'? Action (state): action;} at this point, the study of "how useState executes the process" is over. I hope I can solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report