React useState异步特性导致快速连续更新状态不生效问题排查
错误原因
这个问题是闭包捕获旧值和React状态批处理共同导致的:
- 同一个组件渲染周期内,所有函数拿到的
selected都是本次渲染时的固定值,两次快速触发回调时都处于初始渲染的闭包环境中,所以两次读取的selected都是初始值[] - 短时间内连续调用
setSelected会被React合并批处理,两次更新分别是setSelected([...[], 第一个值])和setSelected([...[], 第二个值]),后者会直接覆盖前者的更新结果,最终数组里只剩第二个值
修正方案
使用useState提供的函数式更新写法即可,函数式更新的入参是React传入的当前最新状态快照,不会受闭包旧值影响:
export const Foo = () => { const [selected, setSelected] = React.useState<any[]>([]); const onSomeFastAction = (value: any) => { console.log(`adding ${value} to selected`) // 改用函数式更新,基于最新状态计算新值 setSelected(prevSelected => [...prevSelected, value]) } React.useEffect(() => { console.log(selected); }, [selected]) return ( <CrazyFastComponentThing onThingThatHappens={onSomeFastAction} /> ) }
修改后两次更新会基于前一次的结果依次计算,最终数组会包含两次传入的值。
内容的提问来源于stack exchange,提问作者pbuzz007
相关产品推荐
相关产品推荐

