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

React数组管理问题:MERN食谱项目食材输入框增删按钮失效求助

动态食材输入框添加/删除失效问题修复

问题核心原因

你的代码里handleAddIngredient和handleRemoveIngredient函数更新state时犯了关键错误:你把新数组赋值给了错误的state字段。

原来的代码中,你创建了newIngredient和updatedIngredient数组,但调用setRecipe时直接用变量名作为键({ ...recipe, newIngredient }),这相当于给state新增了一个newIngredient字段,而非更新原本的ingredient数组。React state不会自动映射变量名到已有字段,导致recipe.ingredient数组始终未被正确更新,渲染的输入框列表没有变化,按钮看起来就像失效了。

修正后的代码

import React from "react";
import { useState } from "react";
import axios from "axios";
import { useGetUserID } from "../Hooks/useGetUserID";
import { useNavigate } from "react-router-dom";

const Create_recipe = () => {
  const userId = useGetUserID();

  // 初始给ingredient数组一个空字符串,确保页面加载时就有一个输入框
  const [recipe, setRecipe] = useState({
    name: "",
    ingredient: [""],
    instruction: "",
    imageUrl: "",
    cookingTime: 0,
    userOwner: userId,
  });

  const navigate = useNavigate();

  const handleChange = (event) => {
    const { name, value } = event.target;
    setRecipe({ ...recipe, [name]: value });
  };

  // 修正:更新state的ingredient字段
  const handleAddIngredient = () => {
    const newIngredient = [...recipe.ingredient, ""];
    setRecipe({ ...recipe, ingredient: newIngredient });
  };

  // 修正:更新state的ingredient字段
  const handleRemoveIngredient = (index) => {
    const updatedIngredient = [...recipe.ingredient];
    updatedIngredient.splice(index, 1);
    setRecipe({ ...recipe, ingredient: updatedIngredient });
  };

  const handleIngredientChange = (event, index) => {
    const { value } = event.target;
    const ingredient = [...recipe.ingredient];
    ingredient[index] = value;
    setRecipe({ ...recipe, ingredient });
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    try {
      await axios.post("http://localhost:3001/recipe/create", recipe, {
        headers: {
          "Content-Type": "application/json",
        },
      });

      alert("recipe created");
      navigate("/");
    } catch (err) {
      if (err.response) alert(JSON.stringify(err.response.data));
    }
  };

  return (
    <div className="createRecipeSession">
      <h2 className="createRecipeHeader">Create Recipe</h2>
      <div className="createRecipeContainer">
        <form onSubmit={handleSubmit} className="createFormDetail">
          <div className="createRecipeSubtitle">
            <label htmlFor="name">Name</label>
          </div>
          <input type="text" id="name" name="name" onChange={handleChange} />

          <div className="createRecipeSubtitle">
            <label htmlFor="ingredients">Ingredients</label>
          </div>
          <div>
            {recipe.ingredient.map((ingredient, index) => (
              <div className="ingredientOption" key={index}>
                <div className="ingredientOption1">
                  <input
                    className="inputIngredient"
                    type="text"
                    name="ingredient"
                    value={ingredient}
                    onChange={(event) => handleIngredientChange(event, index)}
                  />
                </div>

                <div className="ingredientOption2">
                  {recipe.ingredient.length > 1 && (
                    <button
                      className="removeIngredient"
                      type="button"
                      onClick={() => handleRemoveIngredient(index)}
                    > - </button>
                  )}
                </div>
              </div>
            ))}
            <button
              className="addIngredient"
              type="button"
              onClick={handleAddIngredient}
            >Add ingredient</button>
          </div>
          
          <div className="createRecipeSubtitle">
            <label htmlFor="instruction">Instruction</label>
          </div>
          <textarea
            id="instruction"
            name="instruction"
            onChange={handleChange}
          />
          <div className="createRecipeSubtitle">
            <label htmlFor="imageUrl">ImageUrl</label>
          </div>
          <input
            type="text"
            id="imageUrl"
            name="imageUrl"
            onChange={handleChange}
          />

          <div className="createRecipeSubtitle">
            <label htmlFor="cookingTime">CookingTime</label>
          </div>
          <input
            type="number"
            id="cookingTime"
            name="cookingTime"
            onChange={handleChange}
          />
          <button className="createRecipeButton" type="submit">
            Create recipe
          </button>
        </form>
      </div>
    </div>
  );
};

export default Create_recipe;

额外优化点

  1. 初始ingredient数组设为[""],确保页面加载时就显示一个输入框,符合用户预期
  2. 删除按钮的判断条件改为recipe.ingredient.length > 1,写法更简洁
  3. 提交请求时改用axios.post的简化写法,并把Content-Type改为application/json(更符合JSON数据传输标准)
  4. 移除了handleIngredientChange里多余的event.preventDefault()(输入框不需要阻止默认行为)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 08:22:56