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

React严格模式下useReducer触发两次致购物车数量重复累加问题

React严格模式下购物车重复累加问题修复

问题表现

  • 开启React严格模式时,开发环境会重复执行reducer等逻辑检测非纯副作用,在不关闭严格模式的前提下,需要保证重复执行逻辑时输出结果一致
  • 购物车添加商品场景:添加数量为3的商品时,逻辑重复执行后最终数量计算为1 + 3 + 3 =7,不符合预期
  • 原有逻辑:购物车无对应商品时通过concat()追加商品项;存在对应商品时定位到对应项修改数量,重复执行时累加逻辑同步执行两次导致数值错误
    添加两次数量到7的bug截图

问题根因

Reducer必须是纯函数,原有代码违反了纯函数要求:

  1. 更新已存在商品时,直接修改了原state中的items数组:const stateItems = state.items; stateItems[itemIndex] = updatedItem是对原状态的直接修改,属于副作用
  2. 严格模式第一次执行reducer时已经修改了原state的商品数量,第二次执行会基于第一次修改后的结果再次累加,最终导致数量翻倍
  3. 存在隐藏逻辑bug:未匹配到对应action类型时直接返回defaultCart,会导致非SUBMIT操作时购物车被意外清空

修复后代码

export const CartContextProvider = props => {
  const defaultCart = { items: [], qty: 0, total: 0 }

  const cartReducer = (state, actions) => {
    if (actions.type === 'SUBMIT') {
      const { id, qty: addQty, price } = actions.item;
      const addNum = +addQty;
      const unitPrice = +price;
      // 非法数量直接返回原状态不更新
      if (addNum <= 0) return state;

      // 查找商品位置
      const itemIndex = state.items.findIndex(el => el.id === id);
      
      // 商品不存在:生成新数组追加新商品
      if (itemIndex === -1) {
        const newItem = {
          id: id,
          qty: addNum,
          price: unitPrice
        };
        return {
          items: [...state.items, newItem],
          qty: state.qty + addNum,
          total: state.total + addNum * unitPrice
        };
      } 
      // 商品已存在:不可变更新对应项
      else {
        const existItem = state.items[itemIndex];
        const updatedItem = {
          ...existItem,
          qty: existItem.qty + addNum
        };
        // 生成新的数组副本,不修改原数组
        const updatedItems = [...state.items];
        updatedItems[itemIndex] = updatedItem;

        return {
          items: updatedItems,
          qty: state.qty + addNum,
          total: state.total + addNum * unitPrice
        };
      }
    }
    // 未匹配action返回当前状态,避免清空购物车
    return state;
  }

  const [cart, dispatchCart] = useReducer(cartReducer, defaultCart)

  function cartSubmitHandler (id, qty, price) {
    dispatchCart({ type: 'SUBMIT', item: { id, qty, price } })
  }

  return (
    <CartContext.Provider
      value={{
        cart: cart,
        cartSubmitHandler: cartSubmitHandler
      }}
    >
      {props.children}
    </CartContext.Provider>
  )
}

export default CartContext

修复说明

  • 所有状态更新遵循不可变原则:对象、数组更新时都生成新的副本,绝不直接修改传入的state参数,保证reducer是纯函数——相同输入无论执行多少次,输出结果完全一致,从根本上适配严格模式的重复检测逻辑
  • 提前拦截非法数量参数,减少无效更新
  • 修复了action不匹配时清空购物车的隐藏bug
  • 移除了调试用的console.log,避免严格模式下重复打印干扰判断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:21:28