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