React中useCallback内setState后如何获取最新状态值
React中setState后在定时器中获取最新state值的解决方案
你遇到的问题是闭包捕获旧值导致的:useCallback会捕获当前渲染周期的player1和player2,而setTimeout的回调会保留这个闭包环境,1秒后执行时拿到的还是更新前的旧值。同时React的setState是异步更新,不能在调用set之后直接拿到新的state值。
下面是两种直接有效的解决方法:
方法一:直接使用局部变量存储新值
既然你已经明确要设置的新值(player1的新值是传入的value,player2的新值是随机生成的结果),可以把这些新值存在局部变量里,直接传给winConditionCheck,完全避开state的闭包问题:
const playerInputHandler = React.useCallback((value) => { // 把新值存在局部变量里 const newPlayer1 = value; const newPlayer2 = Math.floor(Math.random() * 3) + 1; setPlayer1(newPlayer1); setPlayer2(newPlayer2); setTimeout(() => { // 直接用局部变量里的最新值 winConditionCheck(newPlayer1, newPlayer2); }, 1000); }, [winConditionCheck]); // 依赖项只保留winConditionCheck即可
这个方法最简单,也最适配你当前的场景,因为新值是可以提前明确获取到的。
方法二:用useRef同步最新state值
如果后续场景更复杂(比如需要基于旧state计算新值,无法提前拿到明确的新值),可以用useRef来实时同步state的最新状态,这样在任何地方都能获取到最新值:
首先定义ref并同步state:
const player1Ref = React.useRef(player1); const player2Ref = React.useRef(player2); // 每次state更新时,同步ref的current值 React.useEffect(() => { player1Ref.current = player1; player2Ref.current = player2; }, [player1, player2]);
然后修改你的事件处理函数:
const playerInputHandler = React.useCallback((value) => { setPlayer1(value); setPlayer2(Math.floor(Math.random() * 3) + 1); setTimeout(() => { // 从ref中获取最新的state值 winConditionCheck(player1Ref.current, player2Ref.current); }, 1000); }, [winConditionCheck]);
useRef的current属性是可变的,不会受React渲染周期的闭包限制,所以能始终拿到最新的state值。
内容的提问来源于stack exchange,提问作者Fuad
相关产品推荐
相关产品推荐

