The purpose of writing this article is to solve my doubts about the use of useState. I hope it can help you.

The usage of useState is actually quite simple, and it’s easy to read the official documentation to learn how to write it. However, after using it for a while, there is some confusion, such as why the new state can be preserved when the setXXX method returned by useState is triggered to execute again (when the argument passed by useState is the same as before). Why can’t useState be in the if branch? So this article mainly answers these two questions.

Why is it possible to keep the latest state in each render

From my previous programming experience, I can guess that the “state” must be saved somewhere after each call to setXXX, and the value should be taken out from that place when rendering again, so it is easy to write the following code:

// Triggers page re-rendering
function reRender() {
  ReactDOM.render(<App />, document.getElementById("root")); } // Let _innerState = undefined; Function _setInnerState(newState) {_innerState = newState; reRender(); } function useState(initValue) {if (_innerState == null) {_innerState = initValue; } return [_innerState, _setInnerState]; } function Counter() { const [count, setCount] = useState(0); return (<div className="comp">
      <p>{count}</p>
      <button onClick={()= >SetCount (count +1)}> hit me +1</button>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}
Copy the code

UseState is a custom function, not useState from React hooks. The implementation is simple. To ensure that the latest value is retrieved each time you execute the Counter function, use the variable _innerState to store the value after each setCount. The first time useState is called, _innerState is empty, so the passed 0 is assigned to _innerState. When you click the button and add 1, the 1 copy is assigned to _innerState. At this point, the component Counter is rendered again, and the function Counter is executed again. UseState (0) still passes 0, but since this is not the first time useState has been called, So the 0 parameter passed to useState is ignored and the value of the inner variable _innerState is used (which is already 1), so the data rendered to the page is 1 instead of 0

Why can’t useState be in if

You can’t call useState multiple times in the Counter function because only _innerState holds one state. You can’t define multiple states in the Counter function if you use useState multiple times. It’s easy to think of arrays as data structures to store state.

// Triggers page re-rendering
function reRender() {
  ReactDOM.render(<App />, document.getElementById("root")); } // Use an array to store let _innerStateArr = []; let _index = 0; function _setInnerState(index, newValue) { _innerStateArr[index] = newValue; reRender(); // need to reset _index = 0; } const _updateFn = index => newValue => { _setInnerState(index, newValue); }; function useState(initValue) { if (_innerStateArr[_index] == null) { _innerStateArr[_index] = initValue; } const cur = _innerStateArr[_index]; return [cur, _updateFn(_index++)]; } function Counter() {const [name, setName] = useState(" James "); const [count, setCount] = useState(0); function updateData() { setName("kobe.r.i.p" + (count + 1)); setCount(count + 1); } return (<div className="comp">
      <p>{name}</p>
      <p>{count}</p>
      <button onClick={()= >The updateData ()} > I + 1 point</button>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}
Copy the code

The code above should also be easy to read. Use _innerStateArr to store each state. In the Counter function, useState(” James “) is called for the first time, so the value of James is stored in the first place in the array, _innerStateArr[0]=’ James’. UseState (0) is the second call to useState, so the value of 0 is stored in the second location in the array, _innerState[1]=0. So you have the need to call useState multiple times in the function.

Understanding the code above explains why useState cannot be placed in if. UseState determines which state to use based on the order in which you call it. If you put useState in an if, the order is broken, and the state you get with useState is probably wrong, look at this code:

function Counter() {
  const [name, setName] = useState("james");
  if (name === 'james') {// eslint-disable-next-line
    const [other] = useState('other')}const [count, setCount] = useState(0);
  function updateData() {
    setName("kobe.r.i.p" + (count + 1));
    setCount(count + 1);
  }
  return (
    <div className="comp">
      <p>{name}</p>
      <p>{count}</p>
      <button onClick={()= >The updateData ()} > I + 1 point</button>
    </div>
  );
}
Copy the code

The code for the Counter function is basically the same, except that a useState call is added to the if. When Counter is called for the first time, the if branch satisfies the condition, so useState calls Counter three times, and their values are assigned to the _innerStateArr array, The value 0 of count is stored in the third position of the _innerStateArr array. When you click on the button and Counter executes again, the if branch does not meet the criteria, the whole function Counter is called useState twice, useState(0) is called the second time in the Counter function, and since it is called the second time, You get the value other in the second position of the _innerStateArr array, instead of 1. That’s the problem, so you can’t use useState in if.

conclusion

UseState uses two internal variables, _index and _innerState, to store the _innerState and _index on a virtual node. Because the virtual DOM corresponds one-to-one to the real DOM node, each function component is a virtual DOM, so each component has its own _innerState and _index.

Use Estate is the result of react-hooks. Use Estate is the result of react-hooks. Use Estate is the result of react-hooks.