首页 > 其他 > 详细

React Hook 中 useState 异步回调获取不到最新值及解决方案

时间:2021-07-09 23:29:41      阅读:1142      评论:0      收藏:0      [点我收藏+]

预先了解 setState 的两种传参方式

1、传入对象 setState(options);

列如:

const [state, setState] = useState(0);
setState(state + 1);

2、传入回调函数 setState(callBack);

例如:

const [state, setState] = useState(0);
setState((prevState) => prevState + 1); // prevState 是改变之前的 state 值,return 返回的值会作为新状态覆盖 state 值

useState 异步回调获取不到最新值及解决方案

通常情况下 setState 直接使用上述第一种方式传参即可,但在一些特殊情况下第一种方式会出现异常;
例如希望在异步回调或闭包中获取最新状态并设置状态,此时第一种方式获取的状态不是实时的,React 官方文档提到:组件内部的任何函数,包括事件处理函数和 Effect,都是从它被创建的那次渲染中被「看到」的,所以引用的值任然是旧的,最后导致 setState 出现异常:

import React, { useState, useEffect } from ‘react‘;

const App = () => {
  const [arr, setArr] = useState([0]);

  useEffect(() => {
    console.log(arr);
  }, [arr]);

  const handleClick = () => {
    Promise.resolve().then(() => {
      setArr([...arr, 1]); // 此时 arr 为:[0]
    })
      .then(() => {
        setArr([...arr, 2]); // 此时 arr 为旧状态仍然为:[0]
      });
  }

  return (
    <>
      <button onClick={handleClick}>change</button>
    </>
  );
}

export default App;

最后导致结果为 [0, 2]:
技术分享图片
在 class 组件中我们可以使用 setState(options, callBack); 在 setState 的第二个参数回调函数中再次进行 setState,但是 React Hook 中 useState 移除了 setState 的第二个参数,而且若嵌套太多也不佳;

解决方案1:

将上述代码使用第二种(回调)方式传参

const handleClick = () => {
    Promise.resolve().then(() => {
      setArr(prevState => [...prevState, 1]); // 这里也可以不改,使用 setArr([...arr, 1]); 因为这里不需要获取最新状态
    })
      .then(() => {
        setArr(prevState => [...prevState, 2]); // 这里必须改成回调函数传参方式,否则会读取旧状态,导致异常
      });
  }

技术分享图片

解决方案2:

使用 useReducer 仿造类组件中的 forceUpdate 实现页面强制渲染;

import React, { useState, useReducer } from ‘react‘;

const App = () => {
  const [arr, setArr] = useState([0]);
  const [, forceUpdate] = useReducer(x => x + 1, 0);

  const handleClick = () => {
    Promise.resolve().then(() => {
      arr.push(1);
    })
      .then(() => {
        arr.push(2);
        forceUpdate();
      });
  }

  return (
    <>
      <h1>{arr.toString()}</h1>
      <button onClick={handleClick}>change</button>
    </>
  );
}

export default App;

点击前:
技术分享图片

点击后:
技术分享图片

解决方案3:

利用 ref

import React, { useState, useRef, useEffect } from ‘react‘;

const App = () => {
  const [arr, setArr] = useState([0]);
  let ref = useRef();
  useEffect(() => {
    ref.current = arr;
    console.log(arr);
  });

  const handleClick = () => {
    Promise.resolve().then(() => {
      const now = [...ref.current, 1];
      ref.current = now;
      setArr(now);
    })
      .then(() => {
        setArr([...ref.current, 2]);
      });
  }

  return (
    <>
      <h1>{arr.toString()}</h1>
      <button onClick={handleClick}>change</button>
    </>
  );
}

export default App;

技术分享图片

最后附上官方相关文档:为什么我会在我的函数中看到陈旧的 props 和 state ?

React Hook 中 useState 异步回调获取不到最新值及解决方案

原文:https://www.cnblogs.com/hymenhan/p/14991789.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!