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;