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

React中useState嵌套对象值更新异常:一次操作数值累加两次

React useState更新嵌套状态时点击一次累加两次的解决方法

我在React中定义了嵌套结构的useState状态,实现increase函数更新指定item下option的amount时,出现点击一次但amount累加两次的异常:

原状态定义:

const [data, setData] = useState([
  {
    id: 1,
    options: [{ id: 1, amount: 0 }, { id: 2, amount: 0 }]
  },
  {
    id: 2,
    options: [{ id: 1, amount: 0 }, { id: 2, amount: 0 }]
  }
]);

尝试的increase函数:

const increase = (itemId, optionId) => {
    const copy = [...data];

    const dataItem = copy.find((item) => item.id === itemId);
    const option = dataItem.options.find((item) => item.id === optionId);

    option.amount = option.amount + 1;
    setData(copy);
}

问题原因

  1. 浅拷贝导致原状态被修改:[...data]仅复制了数组外层,数组内的item对象、item里的options数组都是原状态的引用,修改option.amount时直接修改了原状态,违反React状态不可变原则。
  2. 严格模式的副作用检测:如果组件启用了React严格模式(Strict Mode),React会刻意执行两次状态更新来检测副作用,这就会导致你的修改被触发两次,出现点击一次累加两次的情况。
  3. 引用修改导致状态检测失效:直接修改引用类型状态会让React无法准确识别状态变化,引发状态不同步或不必要的重渲染。

解决方法

推荐实现:遵循不可变性+函数式更新

使用setData的函数式更新获取最新状态,同时逐层创建新对象/数组,避免修改原引用:

const increase = (itemId, optionId) => {
  setData(prevData => {
    return prevData.map(item => {
      // 不需要修改的item直接返回原对象
      if (item.id !== itemId) return item;

      // 拷贝当前item,并更新options数组
      return {
        ...item,
        options: item.options.map(option => {
          if (option.id !== optionId) return option;
          // 拷贝目标option,更新amount
          return { ...option, amount: option.amount + 1 };
        })
      };
    });
  });
};

备选方式:深拷贝(适合简单数据结构)

如果你的数据结构没有函数、Symbol等特殊类型,也可以用深拷贝来创建完全独立的状态副本:

const increase = (itemId, optionId) => {
  setData(prevData => {
    // 深拷贝创建新的状态副本
    const newData = JSON.parse(JSON.stringify(prevData));
    const targetItem = newData.find(item => item.id === itemId);
    const targetOption = targetItem.options.find(opt => opt.id === optionId);
    targetOption.amount += 1;
    return newData;
  });
};

关键要点

  • 始终遵循React状态不可变原则:不要直接修改状态对象,而是创建新的对象/数组来更新状态。
  • 使用函数式更新(setState(prevState => {...}))确保每次获取的是最新的状态,避免异步更新导致的状态不一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:35:31