Search code examples
reactjsaxiosreact-context

Recipe gets posted but doesn't get saved


I am creating a recipe app with react and axios. When I try to add new recipe by submitting the form in the form.js, it doesn't get saved and displayed along the other recipes, it only gets printed in the console. I suppose it's something with the axios. any idea?.Apreciate any advices guysfull code

form.js

import React from 'react'
import './Form.css'
import {RecipeContext} from './RecipeContext';
import {useContext,useState,useEffect} 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=e=>{
     
      e.preventDefault()
      const newRecipe={name:nazev,description:postup,ingredients:[ingredience],duration:+time,info:uvodni}
      
      
      
      axios.post("https://cookbook.ack.ee/api/v1/recipes", newRecipe)
      .then(res => setRecipes(res.data))
      .catch(error => console.log(error));
      
      
    
    }
    
    return (
        <>
        <button className="pridat" onClick={onSubmit}>+</button>
        <form className="form" >
          <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>+ Přidat</button>
          <input type="text" className="postup" placeholder="Postup"
          value={postup}
          onChange={(e) => setPostup(e.target.value)}/>
         <input type="text" placeholder="Čas" className="cas" value={time}
          onChange={(e) => setTime(e.target.value)}/>
          
        </form>
        </>
    )
          }

export default Form

recipelist.js

import {RecipeContext} from './RecipeContext';
import {useContext} from 'react';
import Recipe from './Recipe';
import './RecipeList.css'
import {Link} from 'react-router-dom'

function RecipeList() {

 const {recipes}=useContext(RecipeContext)
  
  return (
<>
<div className="navbar">
    <h1>Recepty</h1>
    <h3>Počet receptů:{recipes.length}</h3>
  <Link to="/pridat-recept"> <h2 className="plus">+</h2></Link> 
</div>
<div className="recipe-list">
{recipes.map(item=>(
    <Recipe name={item.name} id={item.id} duration={item.duration} score={item.score} key={item.id}/>
))}
</div>
</>

  );
}

export default RecipeList;

recipecontext.js

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


export const RecipeContext=createContext([[],() => {}]);

export default function RecipeProvider(props) {
    const[recipes,setRecipes]=useState([])
    const[state,dispatch]=useReducer(AppReducer,recipes)
    function addRecipe(id){
      dispatch({
        type:'ADD_RECIPE',
        payload:id
      })
    }
  
    useEffect(() => {
  axios.get('https://cookbook.ack.ee/api/v1/recipes?limit=10&offset=0')
  .then(res=>setRecipes(res.data))
  console.log(recipes)
    })   

    
  

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

appreducer.js

export default (state,action)=>{
    switch(action.type){
  
        case 'ADD_RECIPE':
            return{
                ...state,
                recipes:[action.payload,...state.recipes]
            }
        default:
            return state;
    }
}

Solution

  • Since the cookbook API gives you a recipes list whenever you want, you can use it to update the recipes in your app.

    const onSubmit = (e) => {
        e.preventDefault();
        const newRecipe = {
          name: nazev,
          description: postup,
          ingredients: [ingredience],
          duration: +time,
          info: uvodni,
        };
    
        axios
          .post('https://cookbook.ack.ee/api/v1/recipes', newRecipe)
          .then((res) => {
            console.log(res.data); // confirm if it's the new recipe
            updateRecipes();
          })
          .catch((error) => console.log(error));
      };
    

    and in the context, you can add an empty array to useEffect to only run that when component mounts and the updateRecipes function can be placed here as it's one of things we want to be in the context:

    const [recipes, setRecipes] = useState([]);
      // the state below is not being used anywhere so I commented it
      // const [state, dispatch] = useReducer(AppReducer, { recipes });
      const updateRecipes = (id) => {
        axios
          .get('https://cookbook.ack.ee/api/v1/recipes?limit=1000&offset=0')
          .then((res) => setRecipes(res.data));
      };
    
      useEffect(() => {
        axios
          .get('https://cookbook.ack.ee/api/v1/recipes?limit=1000&offset=0')
          .then((res) => setRecipes(res.data));
      }, []);