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

React Strict Mode下useReducer触发重复结果问题排查

Strict Mode下useReducer重复添加元素的解决方案

问题根源

你的reducer函数存在可变操作:虽然用{ ...state }浅拷贝了state对象,但newState.elements还是原数组的引用,调用push会直接修改原数组。而React Strict Mode在开发环境中会重复执行reducer(这是预期行为,用于检测不纯代码),第一次执行时原数组已经被修改,第二次执行push就会再添加一个元素,最终导致每次点击新增两个时间戳。

正确的reducer写法

必须保证reducer是纯函数,永远不要修改原state,而是返回全新的state对象和数组:

const reducer = (state, action) => {
  if (action.type === 'addElement') {
    // 生成新的elements数组,不修改原数组
    return {
      ...state,
      elements: [
        ...state.elements,
        { id: (new Date()).toString() }
      ]
    };
  }
  // 一定要处理默认情况,返回原state
  return state;
};

额外优化点

初始state中的new Date()在Strict Mode下也会被执行两次,导致初始渲染的时间戳其实是两个不同的值(虽然页面只显示一个,但不符合预期)。可以将初始state改为函数形式,确保只执行一次:

const getInitialState = () => ({
  elements: [
    { id: (new Date()).toString() }
  ]
});

// 使用时传入函数
const [state, dispatch] = useReducer(reducer, getInitialState());

完整修正后的代码

import { useReducer } from 'react';

const reducer = (state, action) => {
  if (action.type === 'addElement') {
    return {
      ...state,
      elements: [
        ...state.elements,
        { id: (new Date()).toString() }
      ]
    };
  }
  return state;
};

const getInitialState = () => ({
  elements: [
    { id: (new Date()).toString() }
  ]
});

export default function Test() {
  const [state, dispatch] = useReducer(reducer, getInitialState());

  function addElement() {
    dispatch({ type: 'addElement' });
  }

  return (
    <>
      <h2>Elements</h2>
      {/* 直接遍历elements数组,简化写法 */}
      {state.elements.map((item) => (
        <div key={item.id}>
          <span>{item.id}</span><br />
        </div>
      ))}
      <button type='button' onClick={addElement}>Add Element</button>
    </>
  );
}

关键注意事项

  • reducer必须是纯函数:相同输入必须返回相同输出,不能修改入参,不能有副作用(开发环境Strict Mode的重复执行仅用于检测,生产环境不会触发)。
  • 处理数组/对象时,要创建新的引用,不要直接修改原数据,比如用扩展运算符[...arr]、数组方法(如filter、map)生成新数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 09:23:27