https://github.com/jhconger/FindYourRecipe
Edamam API 一次仅返回 20 个结果。 我想使用“下一个”按钮加载下一组 20 个结果,然后可以选择使用“上一个”按钮返回到上一个结果。我尝试了许多不同的方法来实现这一目标,并进行了大量的搜索来寻找解决方案。 有人能引导我走向正确的方向吗?这是我的一些代码以及存储库的链接:
使用ReactJS 编辑:此代码将允许我在每次更改查询时获取、返回和显示下一组 20 个结果,以及返回到前 20 个结果。 然而,我一直无法弄清楚如何获取结果 41-60 等。我确信我正在错误地处理这个问题,所以任何帮助将不胜感激。
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;
编辑:我通过恢复到 API 的 V1 解决了这个问题,代码如下:
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;
在 20 的第一个响应中,JSON 响应应具有:
"_links":{"next":{"href": "[URL]"
。
此 URL 将返回接下来的 20 个响应(从 21 到 40)