Simple implementation
Let’s start with the state update process
function App(){
const [n,setN]=React.useState(0)
return(
<div className="App">.</div>
)
}
ReactDOM.render(<App/>,root)
Copy the code
When render is called for the first time, App() is executed in Render to get the virtual DOM, and then the real DOM element is created.
When the user clicks the button to call setN, it will render again and call App() again to get the virtual DOM and then dom diff to update dom
UseState (0) is executed every time.
As you can imagine, the component should maintain a state that stores the latest value each time,
let _state;
const myUseState=initialValue= >{
_state=_state===undefined? initialValue:_stateconst setState=newValue= >{
_state=newValue
render()
}
return [_state,setState]
}
const render=() = >{
ReactDOM.render(
<Test/>.document.getElementById("root")); }function Test(){
const [state,setState]=myUseState(0)
function add(){
setState(state+1)}return (
<div>
<button onClick={()= >{add()}}>+1</button>
{state}
</div>)}Copy the code
The test code
However, when you have multiple data, you need an array to hold it
let _state=[];
let index=0
const myUseState=initialValue= >{
const currentIndex=index
_state[currentIndex]=_state[currentIndex]===undefined?
initialValue:_state[currentIndex]
const setState=newValue= >{
_state[currentIndex]=newValue
render()
}
index+=1
return [_state[currentIndex],setState]
}
const render=() = >{
index=0
ReactDOM.render(
<Test/>.document.getElementById("root")); }function Test(){
const [n,setN]=myUseState(0)
const [m,setM]=myUseState(0)
function addN(){
setN(n+1)}function addM(){
setM(m+1)}return (
<div>
<button onClick={()= >{addN()}}>+1</button>
{n}
<button onClick={()= >{addM()}}>+1</button>
{m}
</div>)}Copy the code
Code review
This enables state management of multiple data sets
The point is that useState maintains an array that holds all the declared data in order. Because the array is sorted sequentially, the index is reset every time useState calls render internally, and each component has its own _state and index
UseState order restrictions
But because the data is in order, useState is a problem if you call it in if
const [n,setN]=React.useState(0)
if(n%2= = =0) {const [m,setM]=React.useState(0)}const [k,setK]=React.useState(0)
Copy the code
Code link
This will result in an error and the message must be called hook in exactly the same order
Source analysis
In the source code, each React node corresponds to a FiberNode, which houses a Fiber object. This object records data in a linked list, just like the _state array above
The Hook object set on memoizedState after each call to useState looks like this:
{
baseState,
next,
baseUpdate,
queue,
memoizedState
}
Copy the code
Each useState called in FunctionalComponent has a corresponding Hook object that is stored on Fiber.memoizedState in the order in which it is executed in a linked list format
memoizedState
Used to record the results that should be returned, whilenext
Point to next useuseState
Corresponding object
SetState, which is the second return method of useState, dispatchAction, creates a
var update = {
expirationTime: _expirationTime,
action: action,
callback: callback ! = =undefined ? callback : null.next: null
}
Copy the code
The Update will be added to the queue, possibly with multiple setStates. React will schedule a React update after the Update collection. This will execute a FunctionalComponent, which will execute the corresponding useState and fetch the Hook object. It saves the queue object to indicate which updates exist, performs the updates in turn, takes the latest state and saves it to memoizedState and returns it, finally achieving the setState effect
reference
How do React Hooks implement it