You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React严格模式下结合Map为何会触发两次状态更新?

问题原因解析

1. React StrictMode的核心行为

StrictMode的设计目的是检测代码中的潜在副作用,它会双重执行以下关键函数:

  • 组件初始化函数
  • useState的初始值生成函数
  • useEffect的挂载回调
  • setState的更新函数(即你传给setCountdownTimers的箭头函数)

2. 你的代码中的关键问题

在setState的更新逻辑里,你直接修改了React传入的prevState这个Map实例:

for (const [timerKey, timer] of prevState) {
    prevState.set(timerKey, timer - 1); // 直接修改原状态引用
}
return new Map(prevState);

Map是引用类型,React传递给更新函数的prevState是当前状态的实际内存引用,而非副本。当StrictMode双重执行这个更新函数时:

  • 第一次执行:把prevState中的值从60改成59,返回新Map
  • 第二次执行:此时prevState已经是被修改后的59,再次减1变成58,返回新Map

两次修改的效果叠加,就导致每秒数值直接减2。

3. 为什么换成普通对象可能不会触发这个问题?

如果使用普通对象,正确的更新逻辑是创建新对象而非修改原对象:

setCountdownTimers(prev => {
  return { ...prev, [1]: prev[1] - 1 }; // 基于原对象生成新对象,不修改原引用
});

这种情况下,即使StrictMode双重执行更新函数,两次都是基于原始状态值计算,React会自动忽略重复的更新结果,最终只会生效一次。而你的Map代码直接修改了原引用,才导致两次修改都产生了实际影响。

4. 修复方案

不要直接修改prevState,而是先创建它的副本再修改:

setCountdownTimers((prevState) => {
  const newMap = new Map(prevState); // 先复制原Map生成新实例
  for (const [timerKey, timer] of newMap) {
    newMap.set(timerKey, timer - 1); // 修改副本而非原状态
  }
  return newMap;
});

这样即使更新函数被执行两次,每次都是基于原始状态值计算,两次结果一致,React会自动合并为一次更新,数值就能正常每秒减1。

内容的提问来源于stack exchange,提问作者Plato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:10:14