React+Axios添加食谱失败求助(附完整代码)
问题分析与解决方案
我来帮你梳理下代码里的几个关键问题,这些应该就是导致食谱无法成功添加的核心原因:
1. Axios.post 未传递请求体且无错误处理
你当前的axios.post只传入了API地址,但没有把新建的食谱数据发送给后端,而且没有处理请求的成功/失败回调——这就是为什么没有报错,但数据也没加上的主要原因。另外,你创建的newRecipe里还漏掉了ingredience字段,大概率后端接口是需要这个参数的。
2. Context 中状态管理逻辑混乱
你在RecipeContext里同时混用了useState和useReducer,而且还存在命名错误:定义的方法是addRecipe,但Provider里却写了addTransaction,这会导致调用时直接报错。另外AppReducer的逻辑也不对,你初始传入的state是数组,但reducer里却试图访问state.recipes,这完全不匹配。
3. 表单提交逻辑问题
页面里有两个按钮:一个是外部的+按钮调用onSubmit,另一个是表单内的+ Přidat按钮——这个按钮默认是submit类型,会触发表单的默认提交行为(页面刷新),而且你没有阻止它。另外onSubmit里的逻辑顺序也不对,应该先阻止默认行为,再处理数据。
4. useEffect 无限循环请求
RecipeProvider里的useEffect没有添加依赖数组,会导致组件每次渲染都重复调用axios.get,造成无限循环请求API。
修改后的代码示例
Form.js
import React from 'react' import './Form.css' import { RecipeContext } from './RecipeContext'; import { useContext, useState } from 'react'; import axios from 'axios'; function Form() { const [nazev, setNazev] = useState(''); const [uvodni, setUvodni] = useState(''); const [ingredience, setIngredience] = useState(''); const [postup, setPostup] = useState(''); const [time, setTime] = useState(0); const [score, setScore] = useState(0); const { recipes, setRecipes } = useContext(RecipeContext); const onSubmit = async (e) => { // 先阻止默认提交行为 e.preventDefault(); // 确保所有必填字段都有值(可以根据API要求调整) if (!nazev || !ingredience || !postup) { alert('请填写必填字段!'); return; } const newRecipe = { id: Math.floor(Math.random() * 100000000), description: postup, name: nazev, duration: time, info: uvodni, score: +score, ingredience: ingredience // 补上漏掉的字段 }; try { // 发送POST请求,传递食谱数据 const res = await axios.post("https://cookbook.ack.ee/api/v1/recipes", newRecipe); // 确认API返回成功后,再更新本地状态 setRecipes([...recipes, res.data]); // 清空表单输入 setNazev(''); setUvodni(''); setIngredience(''); setPostup(''); setTime(0); setScore(0); alert('食谱添加成功!'); } catch (err) { // 捕获并打印错误,方便调试 console.error('添加食谱失败:', err.response?.data || err.message); alert('添加失败,请检查控制台信息!'); } }; return ( <> <button className="pridat" onClick={onSubmit}>+</button> <form className="form" onSubmit={onSubmit}> <p className="nazev">Název receptu</p> <input type="text" value={nazev} onChange={(e) => setNazev(e.target.value)} /> <input type="text" className="uvodni" placeholder="Úvodní text" value={uvodni} onChange={(e) => setUvodni(e.target.value)} /> <h2>Ingredience</h2> <input placeholder="Vaše ingredience" type="text" value={ingredience} onChange={(e) => setIngredience(e.target.value)} /> {/* 把这个按钮改成button类型,避免触发表单默认提交 */} <button type="button">+ Přidat</button> <input type="text" className="postup" placeholder="Postup" value={postup} onChange={(e) => setPostup(e.target.value)} /> <input type="number" placeholder="Čas" className="cas" value={time} onChange={(e) => setTime(e.target.value)} /> </form> </> ); } export default Form;
RecipeContext.js
import React, { useState, useEffect, createContext } from 'react'; import axios from 'axios'; export const RecipeContext = createContext([[], () => {}]); export default function RecipeProvider(props) { const[recipes,setRecipes]=useState([]) useEffect(() => { // 添加空依赖数组,只在组件挂载时请求一次 axios.get('https://cookbook.ack.ee/api/v1/recipes?limit=10&offset=0') .then(res=>setRecipes(res.data)) .catch(err => console.error('获取食谱列表失败:', err)) }, []) return ( <RecipeContext.Provider value={{recipes,setRecipes}}> {props.children} </RecipeContext.Provider> ) }
额外调试建议
- 打开浏览器的开发者工具(F12),切换到Network标签,查看POST请求的状态码和响应内容,确认后端是否返回了错误信息。
- 确认后端API的请求参数要求,比如字段名是否和你发送的一致(比如
ingredience是否需要复数形式ingredients)。 - 测试时可以先在
onSubmit里console.log(newRecipe),确认数据格式是否正确。
内容的提问来源于stack exchange,提问作者jendazedniik
相关产品推荐
相关产品推荐

