Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Miguelcds/Recipe-Hub/llms.txt

Use this file to discover all available pages before exploring further.

Recipe Hub lets you save recipes to a favorites list. Favorites persist across page refreshes using the browser’s localStorage, so your saved recipes are still there when you return.
Favorites are stored as an array of meal IDs under the localStorage key "favorites". Only IDs are stored — recipe data is fetched fresh when you view the favorites page.
Favorites are stored in your browser’s localStorage. Clearing your browser data or browsing in a private window will remove your saved favorites.

FavoritesContext

The favorites system is built around a React context that provides favorites state and actions to any component in the tree.
FavoritesContext.jsx
import { createContext, useState, useContext, useEffect } from 'react'

const FavoritesContext = createContext()

export const FavoriteProvider = ({ children }) => {
  const [favorites, setFavorite] = useState(() => {
    const prev = localStorage.getItem('favorites')
    return prev ? JSON.parse(prev) : []
  })

  useEffect(() => {
    localStorage.setItem('favorites', JSON.stringify(favorites))
  }, [favorites])

  const toggleFavorite = (id) => {
    setFavorite((prev) => {
      if (prev.includes(id)) {
        return prev.filter((f) => f !== id)
      }
      return [...prev, id]
    })
  }

  const isFavorite = (id) => favorites.includes(id)

  return (
    <FavoritesContext.Provider value={{ favorites, toggleFavorite, isFavorite }}>
      {children}
    </FavoritesContext.Provider>
  )
}

export const useFavorites = () => useContext(FavoritesContext)

localStorage persistence

The context handles persistence in two places:
1

Initialize from storage

The useState initializer reads from localStorage when the provider first mounts. If a "favorites" entry exists, it’s parsed and used as the initial state. Otherwise the list starts empty.
const [favorites, setFavorite] = useState(() => {
  const prev = localStorage.getItem('favorites')
  return prev ? JSON.parse(prev) : []
})
2

Sync on every change

A useEffect writes the current favorites array back to localStorage whenever it changes. This keeps storage in sync without any manual save step.
useEffect(() => {
  localStorage.setItem('favorites', JSON.stringify(favorites))
}, [favorites])

toggleFavorite

Calling toggleFavorite(id) adds the ID if it isn’t already in the list, or removes it if it is:
const toggleFavorite = (id) => {
  setFavorite((prev) => {
    if (prev.includes(id)) {
      return prev.filter((f) => f !== id) // remove
    }
    return [...prev, id] // add
  })
}
Because the update uses the functional form of setFavorite, it always operates on the latest state — avoiding stale closure issues.

isFavorite

isFavorite(id) returns true if the given ID is in the favorites list. It’s used in RecipeDetailCard to control the button label:
const { isFavorite, toggleFavorite } = useFavorites()

<button onClick={() => toggleFavorite(recipe.id)}>
  {isFavorite(recipe.id) ? "💔 Remove from Favs" : "❤️ Add to Favs"}
</button>

Favorites page

The Favorites page reads the list of favorite IDs from context, then fetches all their full recipe objects in parallel using Promise.all and getRecipeById. The results are stored in local state and passed to RecipeList for rendering.
Favorites.jsx
import React, { useEffect, useState } from "react"
import { useFavorites } from "../context/FavoritesContext"
import { getRecipeById } from "../services/api"
import RecipeList from "../components/RecipeList"

const Favorites = () => {
  const { favorites } = useFavorites()
  const [recipes, setRecipes] = useState([])

  useEffect(() => {
    if (!favorites.length) return

    const fetchRecipe = async () => {
      try {
        const data = await Promise.all(
          favorites.map(id => getRecipeById(id))
        )
        setRecipes(data)
      } catch (error) {
        console.error(error)
      }
    }

    fetchRecipe()
  }, [favorites])

  if (!favorites.length) return (
    <p style={{ textAlign: "center", fontSize: "20px" }}>
      No Has Añadido Nada a Favoritos
    </p>
  )

  return (
    <div>
      <RecipeList recipes={recipes} />
    </div>
  )
}

export default Favorites
All saved recipe details are fetched together via Promise.all, so the grid populates in one batch. If no favorites have been saved, an empty-state message is shown.