Skip to content

useState如何拿到最新的state

Posted on:September 7, 2022

在 React 类组件中,可以通过 this.setState 的第二个参数 callback 拿到最新的 state 值

但是在 hooks 中,useState 没有第二个参数,并且根据 React 的执行机制,每次渲染 hooks 函数都是独立的,引用官网:

组件内部的任何函数,包括事件处理函数和 effect,都是从它被创建的那次渲染中被「看到」的。

也就是组件内部的函数拿到的总是定义它的那次渲染中的 props 和 state(闭包陷阱, 即每次渲染都是独立的闭包

import React, { useState } from "react";

function Example1() {
  const [number, setNumber] = useState(0);
  const alertNumber = () => {
    setTimeout(() => {
      alert(number);
    }, 3000);
  };
  return (
    <div>
      <p>{number}</p>
      <button onClick={() => setNumber(number + 1)}>+</button>
      <button onClick={alertNumber}>alertNumber</button>
    </div>
  );
}

export default Example1;

参考上面的代码,当点击+时,在点击 alertNumber,此时在 3 秒内,再次点击+,3 秒后 alert 出的 number 依旧是三秒前的那个 number,因为在 setTimeout 内形成了闭包

方案一

直接把最新的值作为参数传入进去:

function onStateChange(newState) {
  setState(newState);
  getNewState(newState);
}

function getNewState(newVal) {
  console.log(newVal); // 打印出的就是最新的state
}

方案二

通过 useRef 保存:

const [state, setState] = useState("");
const stateRef = useRef(null);

useEffect(() => {
  stateRef.current = state; // 每次更新时将最新的state赋值给ref
}, [state]); // 这里需要将state作为依赖

function onStateChange(newState) {
  setState(newState);
  setTimeout(getNewState, 0); // 一定要设置一个延迟
}

function getNewState(newVal) {
  console.log(newVal);
}