The value of useState in the callback function is wrong

The value of useState in the callback function is wrong

1. Problems arise

There is such a scenario: a background interface query takes too long, and when the return is successful, other functions are called and the useState value id is passed as a parameter, but the id has been changed while waiting for the interface to return; at this time, the bug appears Yes, when the id is passed as a parameter, the id at this time is still the value when the interface is called.

pseudocode:

import React, {
    
     useState} from 'react';
import ReactDOM from 'react-dom';
const DomeApp = (props) => {
    
    
    const [id, setId] = useState(1);
    // 接口调用
    const requestApi = () => {
    
    
        // 利用setTimeout模拟接口请求
        setTimeout(() => {
    
    
          console.log(id, "setTimeout======");
        }, 5000);
    };
    return 
    (<div>
        <button onClick={
    
    requestApi}>发起请求</button>
        <button onClick={
    
    () => setId((cur) => cur + 1)}>id更改</button>
    </div>)
}

After the above code is clicked 发起请求, click twice quickly id更改; after 5 seconds, the print id is1

2. Solutions

  1. Determine whether the setId method is effective and whether the id value is changed;
  2. Determine from which scope the id value obtained during printing is obtained;

3. Actual operation

We need to modify the above code:

import React, {
    
     useState} from 'react';
import ReactDOM from 'react-dom';
const DomeApp = (props) => {
    
    
    const [id, setId] = useState(1);
    // 接口调用
    const requestApi = () => {
    
    
        console.log(id, "requestApi======");
        // 利用setTimeout模拟接口请求
        setTimeout(() => {
    
    
          console.log(id, "setTimeout======");
        }, 5000);
    };
    return (<div>
     	<h2>{
    
    id}</h2>
        <button onClick={
    
    requestApi}>发起请求</button>
        <button onClick={
    
    () => setId(id+1)}>id更改</button>
    </div>)
}

Operation process: After clicking 发送请求, click twice quickly id更改; at this time, the id on the page increases accordingly, and is excluded setId未生效; while the id is printed for the first time in the interface function as 1, it is still 5 seconds later 1;

Conclusion: The id value obtained after 5 seconds is the id value in the scope of calling the requestApi function, and the id value defined in DomeApp is not obtained.

4. The cause of the problem

Any function inside the component, including event handlers and effects, is "seen" from the render it was created in. In layman's terms, a new state is generated after each setState, and the old state id value is accessed in setTimeout in the requestApi function.

Please refer to the official documentation for details: Why do I see stale props and state in my function?

5. Solutions

use ref

import React, {
    
     useState, useEffect, useRef} from 'react';
import ReactDOM from 'react-dom';
const DomeApp = (props) => {
    
    
    const [id, setId] = useState(1);
    const ref = useRef();
    ref.current = id;
    // useEffect(() => {
    
    
    //     ref.current = id;
    //  });
    // 接口调用
    const requestApi = () => {
    
    
        console.log(id,ref.current, "requestApi======");
        // 利用setTimeout模拟接口请求
        setTimeout(() => {
    
    
          console.log(ref.current, "setTimeout======");
        }, 5000);
    };
    return (<div>
     	<h2>{
    
    id}</h2>
        <button onClick={
    
    requestApi}>发起请求</button>
        <button onClick={
    
    () => setId(id+1)}>id更改</button>
    </div>)
}

Guess you like

Origin blog.csdn.net/IO14122/article/details/126536410