0

https://github.com/jhconger/FindYourRecipe

Edamam API only returns 20 results at a time. I would like to load the next set of 20 results with a "next" button then have the option to return to the previous results with a "prev" button. I have tried many different methods to achieve this and done lots of searches for a solution. Could anyone guide me in the right direction? Here is some of my code as well as a link to the repository:

Using ReactJS edit: this code will allow me to fetch, return, and display the next set of 20 results, every time the query is changed, as well as return to the previous 20 results. However, I have not been able to figure out how to fetch results 41-60, etc. I am sure that I am approaching this incorrectly so any help would be greatly appreciated.

import logo from './logo.svg';
import './App.css';
import styled from 'styled-components'
import 'bootstrap/dist/css/bootstrap.min.css';
import {Navbar, Container, Nav, Form, FormControl, Button} from 'react-bootstrap';
import RecipeBox from './RecipeBox';
import React, {useEffect, useState} from 'react';
import ReactLoading from "react-loading";
import LoadingScreen from "./LoadingScreen";

const AppIcon = styled.img`
display: flex;
flex-direction: row;
align-items: center;
height: 75px;
width: 75px;
`;

const App =()=> {

    const APP_ID = "2d320d45";
    const APP_KEY = "07015b8fb7809a5ee4afdbe546b5d4b7";
    const [recipes, setRecipes] = useState ([]);
    const [next, setNext] = useState ([]);
    const [nextRecipes, setNextRecipes] = useState ([]);
    const [search, setSearch] = useState('');
    const [query, setQuery] = useState("chicken")

    useEffect(() => {
        getRecipes()
    }, [query, next]);

    useEffect(() => {
        getNext()
    }, []);

    useEffect(() => {
        getNextRecipes()
    }, []);

    const getRecipes = async () => {
        const response = await fetch(`https://api.edamam.com/api/recipes/v2?type=public&q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`)
        const data = await response.json();
        setNext(data._links.next.href)
        setRecipes(data.hits);
        console.log(next);
        getNextRecipes();
    };

    const getNext = async () => {
        const response = await fetch(response)
        console.log(response)
        const data = await response.json();
        console.log(data.hits)
        setNext(data._links.next.href)
        setNextRecipes(data.hits);
    };

    const getNextRecipes = async () => {
        const response = await fetch(next)
        console.log(response)
        const data = await response.json();
        console.log(data.hits)
        setNextRecipes(data.hits);
    };

    const updateSearch = e =>{
        setSearch(e.target.value)
    };

    const updateNext = e =>{
        setNext(e.target.value)
    };

    const updateRecipes = e =>{
        setRecipes(nextRecipes)
    };

    const getSearch = e => {
    e.preventDefault();
    setQuery(search)
        setSearch('');
    };

    const [loading, setLoading] = useState(true)
    useEffect(() => {
        setTimeout(() => setLoading(false), 6000)
    }, [])

    return (
        <>
            <Navbar bg="black" expand="lg" variant="dark">
                <Container fluid>
                    <AppIcon src='/RecipeLogo.svg'/>
                    <Navbar.Brand href="/home">Recipes for the Ages</Navbar.Brand>
                    <Navbar.Toggle className="navbar-toggle" aria-controls="navbarScroll"></Navbar.Toggle>
                    <Navbar.Collapse className="navbar-collapse" id="navbarScroll">
                        <Nav className="me-auto my-2 my-lg-3" style={{maxHeight:'100px'}} navbarScroll>

                        </Nav>
                        <Form onSubmit={getSearch} className="d-flex">
                            <FormControl type="search" placeholder="Search Recipes" className="me-2" value={search} onChange={updateSearch} aria-label="search"></FormControl>
                            <Button className="search-btn" variant="secondary" type="submit">
                                <h5>Search</h5>
                            </Button>
                        </Form>
                    </Navbar.Collapse>

                </Container>
            </Navbar>
            {recipes.length > 0 ?(
                <section className="hero">
            <div className= "container">
                <div className="grid">
                    {recipes.map(recipe =>(
                        <RecipeBox
                        key = {recipe._links.self}
                        title ={recipe.recipe.label}
                        image ={recipe.recipe.image}
                        calories ={recipe.recipe.calories}
                        ingredients ={recipe.recipe.ingredients}
                        link ={recipe.recipe.url}
                        ingredients={recipe.recipe.ingredients}
                        source={recipe.recipe.source}
                        healthLabels={recipe.recipe.healthLabels}
                        servings={recipe.recipe.yield}
                        />
                    ))}
                </div>
                <div className="d-flex justify-content-between">
                    <Button className="prev-btn" variant="secondary"  onClick={getRecipes}type="submit" >Previous</Button>
                    <Button className="next-btn" variant="secondary"  onClick={updateRecipes} type="submit">Next</Button>
                </div>

            </div>

                </section>

            ):(
                    <h2>Sorry !! No Recipes Found</h2>
                )}
        </>
  );
}

export default App;

EDIT: I solved this by reverting to V1 of the API and here is the code:

import logo from './logo.svg';
import './App.css';
import styled from 'styled-components'
import 'bootstrap/dist/css/bootstrap.min.css';
import {Navbar, Container, Nav, Form, FormControl, Button} from 'react-bootstrap';
import RecipeBox from './RecipeBox';
import React, {useEffect, useState, useRef} from 'react';
import ReactLoading from "react-loading";
import LoadingScreen from "./LoadingScreen";
import axios from 'axios';

const AppIcon = styled.img`
display: flex;
flex-direction: row;
align-items: center;
height: 75px;
width: 75px;
`;

const App = () => {
    const APP_ID = process.env.REACT_APP_API_ID;
    const APP_KEY = process.env.REACT_APP_API_KEY;
    const [recipes, setRecipes] = useState([]);
    const [currentPage, setCurrentPage] = useState(1);
    const [search, setSearch] = useState('');
    const [query, setQuery] = useState("chicken")
    const [pagination, setPagination] = useState(0);
    const [currentPagination, setCurrentPagination] = useState(0);
    const [page, setPage] = useState(1);
    const prevSearchIdRef = useRef();

    useEffect(() => {
        prevSearchIdRef.current = query;
    });

    const prevSearch = prevSearchIdRef.current
    const fetchRecipes = async () => {
        if (prevSearch !== query) {

        }

        const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}&from=${currentPagination}&to=${pagination + 20}`)
        const data = await response.json();
        console.log(response);
        setRecipes(data.hits);
        console.log(currentPagination);
    };

    const updateSearch = e => {
        setSearch(e.target.value);
    };

    const getSearch = e => {
        e.preventDefault();
        setQuery(search);
        setSearch('');
    };

    const prevClick = () => {
        if (pagination === 0) {
            return;
        }
        ;
        setPagination(pagination - 20);
        setCurrentPagination(currentPagination - 20);
        console.log(pagination);
    };

    const nextClick = () => {
        setPagination(pagination + 20);
        setCurrentPage(+1);
        setCurrentPagination(currentPagination + 20);
        console.log(pagination);
    };

    useEffect(() => {
        fetchRecipes();
    }, [query, pagination]);

    return (
        <>
            <Navbar bg="black" expand="lg" variant="dark">
                <Container fluid>
                    <AppIcon src='/RecipeLogo.svg'/>
                    <Navbar.Brand href="/home">Recipes for the Ages</Navbar.Brand>
                    <Navbar.Toggle className="navbar-toggle" aria-controls="navbarScroll"></Navbar.Toggle>
                    <Navbar.Collapse className="navbar-collapse" id="navbarScroll">
                        <Nav className="me-auto my-2 my-lg-3" style={{maxHeight: '100px'}} navbarScroll>

                        </Nav>
                        <Form onSubmit={getSearch} className="d-flex">
                            <FormControl type="search" placeholder="Search Recipes" className="me-2" value={search}
                                         onChange={updateSearch} aria-label="search"></FormControl>
                            <Button className="search-btn" variant="secondary" type="submit">
                                <h5>Search</h5>
                            </Button>
                        </Form>
                    </Navbar.Collapse>

                </Container>
            </Navbar>
            {recipes.length > 0 ? (
                <section className="hero">
                    <div className="container">
                        <div className="grid">
                            {recipes.map(recipe => (
                                <RecipeBox
                                    key={recipe.recipe.uri}
                                    title={recipe.recipe.label}
                                    image={recipe.recipe.image}
                                    calories={recipe.recipe.calories}
                                    ingredients={recipe.recipe.ingredients}
                                    link={recipe.recipe.url}
                                    ingredients={recipe.recipe.ingredients}
                                    source={recipe.recipe.source}
                                    healthLabels={recipe.recipe.healthLabels}
                                    servings={recipe.recipe.yield}
                                />
                            ))}
                        </div>
                        <div className="d-flex justify-content-between">
                            <Button className="prev-btn" variant="secondary" onClick={prevClick}
                                    type="submit">Previous</Button>
                            <Button className="next-btn" variant="secondary" onClick={nextClick}
                                    type="submit">Next</Button>
                        </div>

                    </div>

                </section>

            ) : (
                <h2>Sorry !! No Recipes Found</h2>
            )}
        </>
    );
};

export default App;
  • Hi, did you solve this issue? I have the same issue. – iAmBorgy Jan 25 '23 at 05:10
  • I did in a way. I reverted to using the first version of the API with pagination. I am still bothered that I could not find a way to do it with V2 of the API and I exhaustively researched the issue. I even reached out to Edamam support with no luck. – JUSTIN CONGER Jan 31 '23 at 08:57
  • Please let me know if you happen upon a solution to the original issue and good luck! – JUSTIN CONGER Jan 31 '23 at 09:01
  • I solved my issue using a different dropdown framework. I used Edamam API to fetch ingredients only so a `select DD` is only what I need. I was using `Select2` for my dropdown but I didn't get any help using that. So as I was searching for several weeks, I ended up using `tom-select dropdown` which is very easy and with complete documentation. Hope you solve yours too. I wanna help you but I don't know anything about ReactJS. – iAmBorgy Jan 31 '23 at 09:45
  • This is my post regarding `Edamam API on Select2` https://stackoverflow.com/questions/74527460/how-to-load-more-results-in-select2-pagination-using-url-from-json-response – iAmBorgy Jan 31 '23 at 09:47

0 Answers0