No more nonsense, directly on the code:

import { useState } from 'react';
export default function App() {
  let v = null;
  const [flag, toggle] = useState(true);
  if (flag) {
    const s1 = useState(1) [0];
    console.log("s1 is ", s1);
    v = s1;
  } else {
    const s2 = useState(2) [0];
    console.log("s2 is ", s2);
    v = s2;
  }
  return (
    <div>
      <button onClick={()= >toggle(s => ! s)}>Click me</button>
      <h1>v is {v}</h1>
      </div>
  );
}
Copy the code

Does the above code work at all? What are the results? If you try it, you’ll find that clicking the button over and over again will say:

s1 is 1
s2 is 1
s1 is 1
s2 is 1
.....
Copy the code

So, useState can be put in an if else statement, except that they all have a value of 1. Why is that?

React implements Hook.

As many of you probably already know, React keeps all hooks in a linked list. At the same time, in DEV mode, the names of all hooks are stored in an array called hookTypesDev.

During each update, the current Fiber node and the corresponding hook linked list of workInProcess Fiber node will be traversed simultaneously. If a list ends first, that means a different number of hooks. HookTypesDev also ensures that the hooks called must be of the same type.

However, in the code mentioned earlier, there was an if else, but the result was two USestatehooks, so there is no difference between the two linked lists. UseState in the else statement will be treated as useState(1) before React, which explains why the output is always 1.

So, is this a bug or not? How do you solve it?

React Hook is defined as the following structure:

Hook = {
  memoizedState: any,
  baseState: any,
  baseQueue: Update<any, any> | null.queue: UpdateQueue<any, any> | null.next: Hook | null};Copy the code

Personally, I think if you add an ID and compare by ID, then maybe you can solve this problem. However, in general, I think the problem of Hook is not a big problem. Whether it’s worth changing, or whether it’s intentional not to, I don’t know.

Sauce.