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

useReducer dispatch触发两次,移除StrictMode后UI不更新求助

问题描述

我写了一段React代码,原本useReducer的dispatch方法会触发两次。查资料后移除了index.js里的React.StrictMode,dispatch现在能正常执行一次,但UI不会渲染更新后的slots值,求解决办法。

相关代码

Reservations组件代码

import React, { useReducer, useState } from "react";

import "../App.css";

const initialState = [
  { time: "17:00", slots: 3 },
  { time: "18:00", slots: 4 },
  { time: "19:00", slots: 2 },
  { time: "20:00", slots: 4 },
  { time: "21:00", slots: 3 },
  { time: "22:00", slots: 2 },
];

const reducer = (state, action) => {
  switch (action.type) {
    case "update": {
      let index = state.findIndex((x) => x.time === action.value);
      console.log(index);
      if (state[index].slots > 0) {
        state[index].slots -= 1;
      }
      console.log(state);
      return state;
    }
  }
};

function Reservations() {
 const [availableTimes, dispatch] = useReducer(reducer, initialState);
 const [time, setTime] = useState("17:00"); // 补充原代码缺失的状态声明

 const handleSubmit = (e) => {
 e.preventDefault();
    dispatch({ type: "update", value: time });
  };

   return (
 <>
 <label htmlFor="res-time">选择时间</label>
        <select
          id="res-time"
          value={time}
          onChange={(e) => setTime(e.target.value)}
        >
          {availableTimes.map((availableTime) => {
            return (
              <option key={availableTime.time} value={availableTime.time}>
                {availableTime.time} - 剩余{availableTime.slots}个预约位
              </option>
            );
          })}
        </select>
        <form onSubmit={handleSubmit}>
          <button type="submit">确认预约</button>
        </form>
 </>
  );
}

export default Reservations;

index.js代码

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  // <React.StrictMode>
  <BrowserRouter>
    <App />
  </BrowserRouter>
  // </React.StrictMode>
);
解决方案

核心问题是你在reducer里直接修改了原state的引用,React依赖状态的引用变化来判断是否需要重新渲染组件。必须返回全新的状态对象/数组,不能直接修改原state。

修改reducer函数如下:

const reducer = (state, action) => {
  switch (action.type) {
    case "update": {
      return state.map(item => {
        if (item.time === action.value && item.slots > 0) {
          // 返回新对象,不修改原数据
          return { ...item, slots: item.slots - 1 };
        }
        // 未修改的项直接返回原对象
        return item;
      });
    }
    // 处理默认情况,避免返回undefined
    default:
      return state;
  }
};

关键说明:

  1. 使用map创建新数组,替代直接修改原数组的操作
  2. 对需要更新的项,用扩展运算符...复制原对象的所有属性,再修改slots值,保证返回新引用
  3. 添加default分支,确保任何未知action类型都能返回原state,避免潜在报错
  4. 原代码缺失time状态的声明,已补充完整,否则select组件会出现运行错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:13:18