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

Redux Toolkit状态更新问题:如何为指定食材对象添加并更新ingredientMeasurementUpdate键值对

精准更新Redux中指定食材字段的解决方案

我一眼就看到几个关键问题,咱们一步步捋清楚,把这个状态更新的问题解决掉:

1. 核心问题:Reducer把数组当成对象处理了

先看你updateFields的代码:

updateFields: (state, action) => {
  state.ingrediants = { ...state.ingrediants, ...action.payload };
},

原来的state.ingrediants是数组,你用对象展开语法{...}直接把它转成了带索引键的对象,还把action.payload里的字段直接挂在了这个对象上——这就是Redux DevTools里数组变对象、全局多了个ingredientMeasurementUpdate的原因。

另外提一句:你整个代码里的ingrediants都多写了一个i,正确拼写是ingredients,虽然不影响运行,但这种不一致很容易搞晕自己,后面我会统一修正。

2. 组件层缺失关键信息:没告诉Redux要更新哪个食材

你的RecipeList里所有食材共用同一个ingredientMeasurementUpdate状态,提交时只传了数值,没传递目标食材的ID。这就像你去超市说“我要改价格”却不说改哪个商品,系统肯定不知道该操作谁。


解决方案分步走

第一步:修复Reducer的更新逻辑

我们需要遍历食材数组,精准找到对应ID的食材,只更新它的ingredientMeasurementUpdate字段:

import { createSlice } from '@reduxjs/toolkit';

const initialState = { ingredients: [] }; // 修正拼写
export const ingredientsSlice = createSlice({
  name: "ingredientList",
  initialState,
  reducers: {
    addIngredients: (state, action) => {
      // 新增食材时默认给ingredientMeasurementUpdate赋值0
      state.ingredients = [...state.ingredients, {
        ...action.payload,
        ingredientMeasurementUpdate: 0
      }];
    },
    removeIngredients: (state, action) => { // 修正拼写
      state.ingredients = state.ingredients.filter(
        (i) => i.id !== action.payload.id
      );
    },
    // 把action改名,更清晰表达意图
    updateIngredientMeasurement: (state, action) => {
      const { id, updateValue } = action.payload;
      state.ingredients = state.ingredients.map(ingredient => {
        if (ingredient.id === id) {
          // 只更新目标食材的指定字段,其余保持不变
          return {
            ...ingredient,
            ingredientMeasurementUpdate: Number(updateValue) // 转成数字,和初始类型一致
          };
        }
        return ingredient;
      });
    },
  },
});

// 修正导出的action名
export const { addIngredients, removeIngredients, updateIngredientMeasurement } = ingredientsSlice.actions;
export default ingredientsSlice.reducer;

第二步:修改RecipeList组件,传递目标食材ID

每个食材的表单需要关联自己的ID,提交时把ID和更新值一起传给Redux:

import { memo, useSelector, useDispatch } from 'react-redux';
import { updateIngredientMeasurement } from './ingredientsSlice';

export const RecipeList = memo(() => {
  const ingredientList = useSelector(
    (state) => state.ingredientList.ingredients // 修正拼写
  );
  const dispatch = useDispatch();

  // 每个表单提交时带上当前食材的ID
  const handleSubmit = (e, ingredientId) => {
    e.preventDefault();
    const inputValue = e.target.elements.updateInput.value;
    dispatch(
      updateIngredientMeasurement({
        id: ingredientId,
        updateValue: inputValue
      })
    );
    // 清空输入框
    e.target.elements.updateInput.value = "";
  };

  return (
    <div>
      <div>
        {ingredientList.map((ingredient) => (
          <div className="border-gray-800 border h-52 w-full p-4" key={ingredient.id} >
            <p className="mb-2">{`${ingredient.ingredientMeasurement}${ingredient.ingredientUnit} ${ingredient.ingredientName}`}</p>
            <p className="mb-2">当前更新值: {ingredient.ingredientMeasurementUpdate}</p>
            <form onSubmit={(e) => handleSubmit(e, ingredient.id)}>
              <fieldset className="mb-2">
                <input 
                  className="border-2 p-1" 
                  type="text" 
                  name="updateInput"
                  placeholder="输入更新数值"
                />
              </fieldset>
              <fieldset>
                <button type="submit" className="border-2 p-1">更新</button>
              </fieldset>
            </form>
          </div>
        ))}
      </div>
    </div>
  );
});

第三步:修正其他拼写细节(可选但推荐)

比如IngrediantsForm组件里的变量名和ID,统一拼写避免后续踩坑:

import { memo, useState, useCallback, useDispatch } from 'react';
import { addIngredients } from './ingredientsSlice';
import { v4 as uuidV4 } from 'uuid';

export const IngredientsForm = memo(() => { // 修正组件名
  const dispatch = useDispatch();
  const [ingredientName, setIngredientName] = useState(""); // 修正拼写
  const [ingredientMeasurement, setIngredientMeasurement] = useState(""); // 修正拼写
  const [ingredientUnit, setIngredientUnit] = useState(""); // 修正拼写

  const onFormSubmit = useCallback(
    (e) => {
      e.preventDefault();
      dispatch(
        addIngredients({
          ingredientName,
          ingredientMeasurement: Number(ingredientMeasurement), // 转成数字
          ingredientUnit,
          id: uuidV4(),
        })
      );
      // 清空表单
      setIngredientName("");
      setIngredientMeasurement("");
      setIngredientUnit("");
    },
    [ingredientName, ingredientMeasurement, ingredientUnit, dispatch]
  );

  return (
    <form onSubmit={onFormSubmit} className="space-y-2 p-4 border-2 w-80">
      <fieldset>
        <input 
          className="border-2 p-1 w-full" 
          type="text" 
          value={ingredientName} 
          id="ingredientname" // 修正拼写
          onChange={(e) => setIngredientName(e.target.value)} 
          placeholder="食材名称"
        />
      </fieldset>
      <fieldset>
        <input 
          className="border-2 p-1 w-full" 
          type="number" 
          value={ingredientMeasurement} 
          id="ingredientmeasurement" // 修正拼写
          onChange={(e) => setIngredientMeasurement(e.target.value)} 
          placeholder="数量"
        />
      </fieldset>
      <fieldset>
        <input 
          className="border-2 p-1 w-full" 
          type="text" 
          value={ingredientUnit} 
          id="ingredientunit" // 修正拼写
          onChange={(e) => setIngredientUnit(e.target.value)} 
          placeholder="单位"
        />
      </fieldset>
      <fieldset>
        <button className="border-2 p-1 w-full bg-gray-100" type="submit"> 添加食材 </button>
      </fieldset>
    </form>
  );
});

为什么这样改就对了?

  1. Reducer层:用map遍历数组,只修改匹配ID的食材项,保持数组结构不变,精准更新目标字段;
  2. 组件层:每个食材表单提交时都带上自己的ID,Redux能明确知道要操作哪个对象;
  3. 类型统一:把输入框的字符串值转成数字,和初始状态的类型保持一致,避免类型不一致的潜在问题;
  4. 拼写统一:修正了所有ingrediants的拼写错误,减少后续维护时的混淆。

现在你再打开Redux DevTools观察状态,数组会保持原结构,ingredientMeasurementUpdate也会正确出现在对应的食材对象里啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 11:07:28