0

I am having passing data returned from Spoonacular i.e. response.data from SearchRecipes to DisplayRecipes. For some reason recipe is being logged as empty.

I am attaching all the relevant code below:

SearchRecipes

import React, { useContext, useState, useEffect } from "react";
import axios from "axios";
import { IngredientsContext } from "../contexts/ingredientsContext";
import DisplayRecipes from "./DisplayRecipes";
import { RecipesContext } from "../contexts/recipesContext";

const URL = "https://api.spoonacular.com/recipes/findByIngredients";
const APIKey = "MyAPIKey";

const SearchRecipes = (props) => {
  const [selectedIngredients, setSelectedIngredients] =
    useContext(IngredientsContext);
  const [recipes, setRecipes] = useContext(RecipesContext);

  const handleIngredientClick = (ingredient) => {
    setSelectedIngredients(selectedIngredients.filter((i) => i !== ingredient));
  };

  const handleClick = async () => {
    try {
      const response = await axios.get(
        `${URL}?ingredients=${selectedIngredients.join(",+")}&apiKey=${APIKey}`
      );
      setRecipes(response.data);
      window.open("http://localhost:3000/displayRecipes");
      console.log(recipes);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <RecipesContext.Provider value={recipes}>
      <div className="pb-5 pt-10 ">
        <div>
          <p className="font-[Poppins] pb-4 font-semibold text-[#464646]">
            My Ingredients
          </p>
          <p
            className={`cursor-pointer ${
              selectedIngredients.length > 0 ? "pb-4" : ""
            }`}
          >
            {selectedIngredients.map((ingredient, index) => (
              <span
                key={index}
                pb-4
                onClick={() => handleIngredientClick(ingredient)}
              >
                {ingredient},
              </span>
            ))}
          </p>
          <div>
            <button
              className="bg-[#ffc107] px-6 rounded-md font-medium font-[Poppins] py-2 text-[1rem]"
              onClick={handleClick}
            >
              Find a recipe
            </button>
          </div>

          {/* {recipes && <DisplayRecipes recipes={recipes} />} */}
        </div>
      </div>
    </RecipesContext.Provider>
  );
};

export default SearchRecipes;

DisplayRecipes

import { RecipesContext } from "../contexts/recipesContext";

const DisplayRecipes = (props) => {
  const [recipes] = useContext(RecipesContext);
  console.log(recipes);
  useEffect(() => {
    document.body.classList.add("page-styles");
    return () => {
      document.body.classList.remove("page-styles");
    };
  }, []);
  return (
    <div>
      <div className="mt-28 ml-4">
        <h1
          className="font-[Acme] text-5xl text-left text-[#ffc107] "
          style={{
            textAlign: "left !important",
            marginLeft: "10px !important",
          }}
        >
          Recipes
        </h1>
        <div></div>
      </div>
    </div>
  );
};

export default DisplayRecipes;

App

import NavBar from "./components/NavBar.jsx";
import MainGrid from "./components/MainGrid.jsx";
import { IngredientsContext } from "./contexts/ingredientsContext.js";
import DisplayRecipes from "./components/DisplayRecipes.jsx";
import { Routes, Route } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { RecipesContextProvider } from "./contexts/recipesContext.js";

const App = () => {
  const [selectedIngredients, setSelectedIngredients] = useState([]);
  const [showRecipes, setShowRecipes] = useState(false);

  const handleRecipeClick = () => {
    setShowRecipes(true);
    window.open("http://localhost:3000/displayRecipes");
  };

  return (
    <RecipesContextProvider>
      {" "}
      <div>
        <IngredientsContext.Provider
          value={[selectedIngredients, setSelectedIngredients]}
        >
          <NavBar />
          <Routes>
            <Route
              path="/"
              element={<MainGrid handleRecipeClick={handleRecipeClick} />}
            />
            <Route path="/displayRecipes" element={<DisplayRecipes />} />
          </Routes>
        </IngredientsContext.Provider>
      </div>
    </RecipesContextProvider>
  );
};

export default App;

recipesContext.js


export const RecipesContext = createContext();

export const RecipesContextProvider = (props) => {
  const [recipes, setRecipes] = useState([]);

  return (
    <RecipesContext.Provider value={[recipes, setRecipes]}>
      {props.children}
    </RecipesContext.Provider>
  );
};

P.S. I am extremely new to react. P.P.S. This is my first question on here so please excuse the formatting.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181

1 Answers1

0

When you look at your app's structure, you will notice that you have two separate RecipesContext providers:

<RecipesContextProvider> // from App
  <Route>
    <SearchRecipes>
        <RecipesContext.Provider> // from SearchRecipes
            <DisplayRecipe>

Now SearchRecipes calls setRecipes on the context defined in App. However, DisplayRecipe gets its recipes from the context defined in `SearchRecipes´.

Each context maintains its own state, and because the context opened in SearchRecipes is empty, you have the problem you have :-).

fjc
  • 5,590
  • 17
  • 36