React17开发模式下useState函数式更新出现意外状态不一致问题
问题根源
这个问题是 React 17 开发模式下 <StrictMode> 严格模式的特性导致的,你的 useState 写法本身没有语法错误。
React 17 的严格模式为了提前检测出代码中不符合规范的副作用,在开发环境会故意两次调用 useState 的函数式更新回调,且两次调用传入的 prev 状态都是更新前的旧值,最终会采用第二次调用返回的结果作为实际要更新的状态。
你把 Date.now() 这种每次执行结果都会变化的非纯逻辑写在了更新回调内部,第一次调用回调时生成了 id 1636301326611,间隔1ms后第二次调用回调又生成了id 1636301326612,第一次的返回结果被直接丢弃,实际状态更新为第二次的 1636301326612,就出现了你看到的日志中id异常跳变的情况。
其他现象解释
- 生产环境无法复现:严格模式的二次调用逻辑只在开发环境生效,生产构建时会被自动移除。
- 直接传对象没有问题:直接传对象的场景下,新状态值是在 setState 调用前就生成完成的,不管更新逻辑被调用多少次,传入的都是同一个状态对象,不会出现值不一致的问题。
修复方案
保证 useState 的函数式更新回调是纯函数,不要在回调内部执行会产生可变结果的逻辑,把这类逻辑移到回调外部即可:
const update = () => { // 把可变值的生成移到回调外部 const id = Date.now(); setState(prev => { console.log('previous id:', prev.id, 'new id:', id); return { id, }; }); };
修改后不管回调被调用几次,使用的id都是同一个值,不会再出现状态和预期不符的问题。
内容的提问来源于stack exchange,提问作者4ae1e1
相关产品推荐
相关产品推荐

