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;
额外优化点
- 初始
ingredient数组设为[""],确保页面加载时就显示一个输入框,符合用户预期 - 删除按钮的判断条件改为
recipe.ingredient.length > 1,写法更简洁 - 提交请求时改用
axios.post的简化写法,并把Content-Type改为application/json(更符合JSON数据传输标准) - 移除了
handleIngredientChange里多余的event.preventDefault()(输入框不需要阻止默认行为)
内容的提问来源于stack exchange,提问作者ksyu1113
相关产品推荐
相关产品推荐

