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

React新增食谱功能报错求助:Axios POST请求失败

问题分析与解决方案

看起来你在React项目中用Axios提交食谱时遇到了不少问题,我帮你梳理下代码里的问题,然后给出修正方案:

核心问题梳理

1. Axios.post 使用错误

你当前的axios.post只传了URL,没有发送请求体(也就是要提交的食谱数据),而且没有处理请求的成功/失败回调,所以会直接报错。另外,你把setRecipes放在Axios请求之前,这会导致本地状态更新了,但如果请求失败,状态就不同步了,应该在请求成功后再更新本地状态。

2. 表单数据遗漏

你收集了ingredience(食材)的状态,但创建newRecipe时没把这个字段加进去,后端大概率需要这个数据,所以会导致请求参数不完整。

3. Context 与 Reducer 混用混乱

你同时用了useState和useReducer来管理recipes状态,而且RecipeProvider的value里写了addTransaction(应该是addRecipe),还有AppReducer的逻辑错误——你的state是数组,却写成了state.recipes,这会导致reducer无法正确更新状态。

4. useEffect 无限循环

你的useEffect没有设置依赖数组,会导致组件每次渲染都发送GET请求,这会造成性能问题,也会打乱你的状态。

5. 表单提交逻辑问题

你把提交按钮放在了<form>标签外面,而且form内的+ Přidat按钮没有阻止默认行为,会导致表单提前提交。


修正后的代码

1. Form.js(主要修正Axios.post和表单逻辑)

import React, { useContext, useState } from 'react'
import './Form.css'
import { RecipeContext } from './RecipeContext';
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, addRecipe } = useContext(RecipeContext)

  const onSubmit = async (e) => {
    e.preventDefault();
    // 确保所有必填字段都有值
    if (!nazev || !postup || !time) {
      alert('请填写必填字段!');
      return;
    }

    const newRecipe = {
      id: Math.floor(Math.random() * 100000000),
      description: postup,
      name: nazev,
      duration: parseInt(time), // 转成数字类型,适配后端要求
      info: uvodni,
      score: parseInt(score),
      ingredients: ingredience // 补上遗漏的食材字段
    };

    try {
      // Axios.post 第二个参数是要发送的请求体数据
      const res = await axios.post("https://cookbook.ack.ee/api/v1/recipes", newRecipe);
      // 请求成功后更新状态(用后端返回的数据更准确)
      addRecipe(res.data);
      // 清空表单
      setNazev('');
      setUvodni('');
      setIngredience('');
      setPostup('');
      setTime(0);
      setScore(0);
      alert('食谱添加成功!');
    } catch (error) {
      console.error('添加食谱失败:', error.response?.data || error.message);
      alert('添加食谱失败,请检查网络或字段格式!');
    }
  }

  return (
    <>
      <form className="form" onSubmit={onSubmit}>
        <p className="nazev">Název receptu</p>
        <input type="text" value={nazev} onChange={(e) => setNazev(e.target.value)} required />
        <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)} />
        {/* 这个按钮用来添加更多食材,设置type="button"避免触发表单提交 */}
        <button type="button">+ Přidat</button>
        <input type="text" className="postup" placeholder="Postup" value={postup} onChange={(e) => setPostup(e.target.value)} required />
        <input type="number" placeholder="Čas" className="cas" value={time} onChange={(e) => setTime(e.target.value)} required />
        {/* 提交按钮放到form内部,用type="submit"触发表单提交 */}
        <button type="submit" className="pridat">+ Přidat recept</button>
      </form>
    </>
  )
}

export default Form

2. RecipeContext.js(修正Reducer和useEffect逻辑)

import React, { useEffect, createContext, useReducer } from 'react';
import axios from 'axios';
import AppReducer from './AppReducer'

export const RecipeContext = createContext();

export default function RecipeProvider(props) {
  // 统一用useReducer管理状态,去掉useState的混用
  const [state, dispatch] = useReducer(AppReducer, []);

  function addRecipe(recipe) {
    dispatch({
      type: 'ADD_RECIPE',
      payload: recipe
    });
  }

  useEffect(() => {
    // 封装请求函数,只在组件挂载时执行一次
    const fetchRecipes = async () => {
      try {
        const res = await axios.get('https://cookbook.ack.ee/api/v1/recipes?limit=10&offset=0');
        dispatch({
          type: 'SET_RECIPES',
          payload: res.data
        });
      } catch (error) {
        console.error('获取食谱失败:', error);
      }
    };
    fetchRecipes();
  }, []); // 空依赖数组,确保只执行一次

  return (
    <RecipeContext.Provider value={{ recipes: state, addRecipe }}>
      {props.children}
    </RecipeContext.Provider>
  )
}

3. AppReducer.js(修正Reducer的状态处理逻辑)

export default (state, action) => {
  switch(action.type) {
    case 'SET_RECIPES':
      return action.payload; // 初始化食谱列表
    case 'ADD_RECIPE':
      return [action.payload, ...state]; // 把新食谱添加到列表开头
    default:
      return state;
  }
}

关键说明

  • Axios.post 正确用法:axios.post(url, data, [config]),第二个参数是要发送的请求体数据,用async/await处理异步逻辑比.then/.catch更清晰易读。
  • 状态更新时机:一定要在请求成功后再更新本地状态,避免请求失败时出现本地状态和后端数据不一致的情况。
  • 表单优化:给必填字段加required属性,用type="number"处理数字输入,避免字符串转数字的潜在问题。
  • Reducer 规范:统一用useReducer管理状态,避免useState和useReducer混用导致的状态管理混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:03:24