React Hooks跨函数调用时useState状态值不同步问题
问题成因
React 函数组件的状态更新是异步批处理机制,调用setShowNew时不会立刻修改当前执行上下文中的状态值,新的状态值只会在下一次组件重渲染时生效。
同时函数组件每一次渲染都会生成独立的闭包快照,当前checkBoxAction、fetchAnswers函数里捕获的showNew,永远是触发这次渲染时的状态值。你在同一个同步执行流里调用setShowNew后立刻执行fetchAnswers,后者读到的还是当前闭包里缓存的旧状态,自然和你传入setShowNew的新值相反。
可行解决方案
根据业务场景选以下任意一种方案即可:
- 方案1:直接传递最新值给调用函数(最简单、性能最好)
你在checkBoxAction中已经拿到了最新的选中值,不需要等状态更新,直接把这个值作为参数传给fetchAnswers即可,完全避开闭包旧值问题:const checkBoxAction = async (status, checkBoxStatus) => { let currentShowNew = showNew; if(status === 'new') { console.log('checkBoxAction: ', checkBoxStatus) setShowNew(checkBoxStatus) currentShowNew = checkBoxStatus } // 直接传入最新值 fetchAnswers(currentShowNew) } // 方法接收参数使用,不再依赖闭包中的状态 const fetchAnswers = async (targetShowNew) => { console.log('fetchAnswers: ', targetShowNew) // 后续逻辑用传入的targetShowNew即可 } - 方案2:通过
useEffect监听状态变化触发逻辑(适合状态变更自动触发副作用的场景)
把数据拉取逻辑放到useEffect的回调中,将showNew加入依赖数组,React会保证状态更新完成、组件重渲染后,才执行effect回调,此时拿到的一定是最新状态:const [showNew, setShowNew] = useState(true); // 监听showNew变化,状态更新完成后自动执行 useEffect(() => { const fetchAnswers = async () => { console.log('fetchAnswers: ', showNew) // 此处拿到的永远是最新的showNew } fetchAnswers() }, [showNew]) const checkBoxAction = async (status, checkBoxStatus) => { if(status === 'new') { console.log('checkBoxAction: ', checkBoxStatus) setShowNew(checkBoxStatus) } // 不需要手动调用fetchAnswers,状态更新后会自动触发 }
注意:不要为了拿到即时状态使用
flushSync强制同步更新,该API会破坏React的批处理优化,带来额外的性能损耗,非极端特殊场景不推荐使用。
内容的提问来源于stack exchange,提问作者Vic Andam
相关产品推荐
相关产品推荐

