This is one of our basic components:

function App() {
  const [count, setCount] = useState(0)

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button type="button" onClick={handleClick}>
      count is: {count}
    </button>)}Copy the code

When we click the button, the number of counts increases by one. If our handleClick had only one statement, we wouldn’t have a problem, but what if our handleClick had the following format:

 function handleClick() {
    setCount(count+1);
    setCount(count+2);
 }
Copy the code

The result can be surprising. If our current count value is 0 and we click the button once, we expect it to change to 3, but it turns out to be 2.

The solution to this problem is to use the callback function:

 function handleClick() {
    setCount((count) = > count+1);
    setCount((count) = > count+2);
 }
Copy the code

What accounts for the difference?

We skip through all the usetState updates and just look at the result, which eventually generates an update queue to hold the value of the state to be updated, and this is where the difference occurs.

The former generates an update queue that looks like this:

When the update queue is generated, it will not be in the update process, and the count value has not been updated, so they are all taken the same. If the initial value of count is 0, then the queue value is fixed 1 -> 2.

The latter looks like this:

These are two functions, and the specific values are not fixed, so we have to calculate them later.

After generating the update queue, we would iterate over the update queue and calculate the final count, which would look something like this:

let newState; // This will be the final state

// This is our update queue, strung together with the next pointer
// For example it could be 1 -> 2 -> 3....
If (count) => count + 1 -> (count) => count + 2
letQueue = a queue;let head = queue;
do {
  if (typeof head === 'function') {
    newState = head(newState); // Key point, look
  } else {
    newState = head;
  }
  head = head.next;
} while(head.next ! =null);
Copy the code

The key is to differentiate between functions. As a result, using functions, we can get the latest count value without actually going through the React update process.

Because of this code, we solved the problem using the callback function.

You might be smart enough to think that the problem is that the two neighboring setcounts are in the same update queue, and if you want to avoid that, just make the second setCount and the first setCount not in the same update queue, and I’ll just update after the first update. So you want to wrap it with an asynchronous task, such as setTimeout.

function handleClick() {
    setCount(count + 1);
    setTimeout(() = > {
      setCount(count + 2);
    }, 1000)}Copy the code

Reality is harsh. No.

They’re not in the same line at this point. Analysis shows that the first setCount is finished, and the second setCount statement is executed after 1 second.

But even if we wrap a layer of setCount statements with setTimeout, because of JavaScript’s closure mechanism, the count in setTimeout is always pointing to the previous one, that is, no matter how long our timer is delayed, It’s the same thing as the count used in setCount(count+1).

No amount of delay is of any use. This is something special about functional components.

If you’re using a Class component, this works (note that it does, but it’s not recommended).

handleClick() {
    this.setState({
      count: this.state.count + 1
    })

    setTimeout(() = > {
      this.setState({
        count: this.state.count + 2})})}Copy the code

Even if the Class component is updated, the State referenced by it is always the same reference. And since setTimeout is not executed until it is updated, it will be new when this.state.count is actually read.

However, this is not recommended to avoid subtle errors, and it is desirable to use the callback whenever reading state:

 this.setState((prevState) = > {
      count: prevState.count + 1
})
Copy the code

Similarly, setCount(count + 1) is fine when used alone, but it is not recommended to avoid unexpected problems. In general, we will also configure this limitation for Lint tools so that code writers do not write it 🙂

Hope this article can answer your doubts, if there is a place that I speak badly, speak not to understand the place, want to see what I write! Tell me, and finally, go ahead and do it.

Morning tuhao a, ordered a egg sausage powder, delicious delicious.