回调函数中useState值有误

回调函数中useState值有误

一、问题产生

有这样一个场景:一个后台的接口查询时间过长,当返回成功时调用其他函数同时将useState值id当做当做参数传递,但在等待接口返回时这个id已经被更改过了;这时候bug就出现了,当把id当做参数传递时,此时的id还是接口调用时的值。

伪代码:

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>)
}

上方代码当点击发起请求后,又迅速点击两次id更改;5秒过后打印id为1

二、解决思路

  1. 判断setId方法是否生效,id值是否更改;
  2. 判断打印时获取的id值是从那个作用域拿到的;

三、实际操作

我们需要改造一下上面的代码:

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>)
}

操作流程: 点击发送请求后,迅速点击两次id更改;此时页面上id随之增加,排除setId未生效;而在接口函数中第一次打印id为1,5秒后依然是1;

结论: 5秒后获取的id值是调用requestApi函数作用域里面的id值,并未获取DomeApp内定义的id值。

四、问题原因

在组件内部的任何函数,包括事件处理函数和 effect,都是从它被创建的那次渲染中被「看到」的。通俗的讲,每次setState后都产生一个新的状态,在requestApi函数中setTimeout里访问的就是旧状态id值。

具体请看官方文档:为什么我会在我的函数中看到陈旧的 props 和 state ?

五、解决方案

使用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>)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值