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

is equivalent to App()

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

memoizedStateUsed to record the results that should be returned, whilenextPoint to next useuseStateCorresponding 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