使用 React 构建食谱查找器网站

介绍

在本博客中,我们将使用 react 构建一个食谱查找网站。该应用程序允许用户搜索他们最喜欢的食谱,查看趋势或新食谱,并保存他们最喜欢的食谱。我们将利用 edamam api 获取实时食谱数据并将其动态显示在网站上。

项目概况

食谱查找器允许用户:

按名称搜索食谱。 查看趋势和新添加的食谱。 查看各个食谱的详细信息。 将食谱添加到收藏夹列表并使用 localstorage 保存数据。 特征 搜索功能:用户可以通过输入查询来搜索食谱。 热门食谱:显示来自 api 的当前热门食谱。 新菜谱:显示来自 api 的最新菜谱。 食谱详细信息:显示有源码搭建wcqh.cn关所选食谱的详细信息。收藏夹:允许用户将食谱添加到收藏夹列表,该列表保存在本地。 使用的技术 react:用于构建用户界面。 react router:用于不同页面之间的导航。 edamam api:用于获取食谱。 css:用于设计应用程序的样式。 项目结构
src/ │ ├── components/ │ └── navbar.js │ ├── pages/ │ ├── home.js │源码搭建wcqh.cn ├── about.js │ ├── trending.js │ ├── newrecipe.js │ ├── recipedetail.js │ ├── contact.js │ └── favorites.js │ ├── app.js ├── index.js ├── app.css └── index.css
登录后复制
安装

要在本地运行此项目,请按照源码搭建wcqh.cn以下步骤操作:

克隆存储库:
git clone https://github.com/abhishekgurjar-in/recipe-finder.git cd recipe-finder
登录后复制
安装依赖项:
npm install
登录后复制
启动 react 应用程序:
npm start
登录后复制

从 edamam 网站获取您的 edamam api 凭证(api id 和 api 密钥)。

在进行 api 调用的页面中添加您的 api 凭据,例如 home.js、trending.js、newrecipe.js 和 recipedetail.js。

用法 源码搭建wcqh.cn 应用程序.js
import react from “react”; import navbar from “./components/navbar”; import { route, routes } from “react-router-dom”; import “./app.css”; import home from “./pages/home”; import about from “./pages/about”; import trend源码搭建wcqh.cning from “./pages/trending”; import newrecipe from “./pages/newrecipe”; import recipedetail from “./pages/recipedetail”; import contact from “./pages/contact”; import favorites from “./pages/favorites”; const app = () =&gt; { re源码搭建wcqh.cnturn ( <navbar></navbar><routes><route path=”/” element=”{&lt;home”></route>} /&gt; <route path=”/trending” element=”{&lt;trending”></route>} /&gt; <route path=”/new-recipe” element=”{&lt;newrecipe”></route>} /&gt; <route path=”/new-recipe” element=”{源码搭建wcqh.cn&lt;newrecipe”></route>} /&gt; <route path=”/recipe/:id” element=”{&lt;recipedetail”></route>} /&gt; <route path=”/about” element=”{&lt;about”></route>} /&gt; <route path=”/contact” element=”{&lt;contact/”>} /&gt; <route path=”/favorites” element=”{&lt源码搭建wcqh.cn;favorites/”>} /&gt; </route></route></routes><div classname=”footer”> <p>made with ❤️ by abhishek gurjar</p> </div> &gt; ); }; export default app;
登录后复制
主页.js

这是用户可以使用 edamam api 搜索食谱的主页。

import react, { usestate, user源码搭建wcqh.cnef, useeffect } from “react”; import { iosearch } from “react-icons/io5”; import { link } from “react-router-dom”; const home = () =&gt; { const [query, setquery] = usestate(“”); const [recipe, setrecipe] = usestate([]); const源码搭建wcqh.cn recipesectionref = useref(null); const api_id = “2cbb7807”; const api_key = “17222f5be3577d4980d6ee3bb57e9f00”; const getrecipe = async () =&gt; { if (!query) return; // add a check to ensure the query is not empty const response = await源码搭建wcqh.cn fetch( `https://api.edamam.com/search?q=${query}&amp;app_id=${api_id}&amp;app_key=${api_key}` ); const data = await response.json(); setrecipe(data.hits); console.log(data.hits); }; // use useeffect to detect chang源码搭建wcqh.cn源码搭建wcqh.cnndle key down event to trigger getrecipe on enter key press const handlekeydown = (e) =&gt; { if (e.key === “enter”) { getrecipe(); } }; return ( <div classname=”home”> <div classname=”home-main”> 源码搭建wcqh.cn <div classname=”home-text”> <h1>find your favourite recipe</h1> </div> <div classname=”input-box”> <span> <input type=”text” placeholder=”enter recipe” onchange=”{(e)”> setquery(e.target.value)} onkeydown={handlekeydown} /源码搭建wcqh.cn/ add the onkeydown event handler /&gt; </span> <iosearch classname=”search-btn” onclick=”{getrecipe}”></iosearch> </div> </div> <div ref=”{recipesectionref}” classname=”recipes”> {recipe.map((item, index) =&gt; ( 源码搭建wcqh.cn <div key=”{index}” classname=”recipe”> @@##@@ <h2 classname=”label”>{item.recipe.label}</h2> <link to={`/recipe/${item.recipe.uri.split(“_”)[1]}`}> <button classname=”button”>view recipe</button> </div> ))} 源码搭建wcqh.cn </div> </div> ); }; export default home;
登录后复制
trending.js

此页面获取并显示趋势食谱。

import react, { usestate, useeffect } from “react”; import { link } from “react-router-dom”; const trending = () =&gt; { const [trendingrecipes源码搭建wcqh.cn, settrendingrecipes] = usestate([]); const [loading, setloading] = usestate(true); const [error, seterror] = usestate(null); const api_id = “2cbb7807”; const api_key = “17222f5be3577d4980d6ee3bb57e9f00”; useeffect(() =&gt; { 源码搭建wcqh.cnconst fetchtrendingrecipes = async () =&gt; { try { const response = await fetch( `https://api.edamam.com/api/recipes/v2?type=public&amp;q=trending&amp;app_id=${api_id}&amp;app_key=${api_key}` ); if (!response.ok) { throw new er源码搭建wcqh.cnror(“network response was not ok”); } const data = await response.json(); settrendingrecipes(data.hits); setloading(false); } catch (error) { seterror(“failed to fetch trending recipes”); setloading(false); 源码搭建wcqh.cn } }; fetchtrendingrecipes(); }, []); if (loading) return ( <div classname=”loader-section”> <div classname=”loader”></div> </div> ); if (error) return <div>{error}</div>; 源码搭建wcqh.cn return ( <div classname=”trending-recipe”> <div classname=”trending-recipe-main”> <div classname=”trending-recipe-text”> <h1>trending recipes</h1> </div> </div> <div classname=”recipes”> {trendi源码搭建wcqh.cnngrecipes.map((item, index) =&gt; ( <div key=”{index}” classname=”recipe”> @@##@@ <h2 classname=”label”>{item.recipe.label}</h2> <link to={`/recipe/${item.recipe.uri.split(“_”)[1]}`}> <button classname=”button”>view recipe</button> 源码搭建wcqh.cn </div> ))} </div> </div> ); }; export default trending;
登录后复制
新菜谱.js

此页面获取新食谱并显示新食谱。

import react, { usestate, useeffect } from “react”; import { link } from “react-router-dom”; const newrecipe = () =&源码搭建wcqh.cngt; { const [newrecipes, setnewrecipes] = usestate([]); const [loading, setloading] = usestate(true); const [error, seterror] = usestate(null); const api_id = “2cbb7807”; const api_key = “17222f5be3577d4980d6ee3bb57e9f00”; use源码搭建wcqh.cneffect(() =&gt; { const fetchnewrecipes = async () =&gt; { try { const response = await fetch( `https://api.edamam.com/api/recipes/v2?type=public&amp;q=new&amp;app_id=${api_id}&amp;app_key=${api_key}` ); if (!response.ok) { 源码搭建wcqh.cn throw new error(“network response was not ok”); } const data = await response.json(); setnewrecipes(data.hits); setloading(false); } catch (error) { seterror(“failed to fetch new recipes”); setloading(false);源码搭建wcqh.cn } }; fetchnewrecipes(); }, []); if (loading) return ( <div classname=”loader-section”> <div classname=”loader”></div> </div> ); if (error) return <div>{error}</div>;源码搭建wcqh.cn return ( <div classname=”new-recipe”> <div classname=”new-recipe-main”> <div classname=”new-recipe-text”> <h1>new recipes</h1> </div> </div> <div classname=”recipes”> {newrecipes.map((item,源码搭建wcqh.cn index) =&gt; ( <div key=”{index}” classname=”recipe”> @@##@@ <h2 classname=”label”>{item.recipe.label}</h2> <link to={`/recipe/${item.recipe.uri.split(“_”)[1]}`}> <button classname=”button”>view recipe</button> </div> 源码搭建wcqh.cn ))} </div> </div> ); }; export default newrecipe;
登录后复制
主页.js

此页面获取并显示主页和搜索的食谱。

import react, { usestate, useref, useeffect } from “react”; import { iosearch } from “react-icons/io5”; import { link } from “react-rou源码搭建wcqh.cnter-dom”; const home = () =&gt; { const [query, setquery] = usestate(“”); const [recipe, setrecipe] = usestate([]); const recipesectionref = useref(null); const api_id = “2cbb7807”; const api_key = “17222f5be3577d4980d6ee3bb5源码搭建wcqh.cn7e9f00″; const getrecipe = async () =&gt; { if (!query) return; // add a check to ensure the query is not empty const response = await fetch( `https://api.edamam.com/search?q=${query}&amp;app_id=${api_id}&amp;app_key=${api_key}` ); 源码搭建wcqh.cn const data = await response.json(); setrecipe(data.hits); console.log(data.hits); }; // use useeffect to detect changes in the recipe state and scroll to the recipe section useeffect(() =&gt; { if (recipe.length &gt; 0 &am源码搭建wcqh.cn源码搭建wcqh.cn== “enter”) { getrecipe(); } }; return ( <div classname=”home”> <div classname=”home-main”> <div classname=”home-text”> <h1>find your favourite recipe</h1> </div> <div classname=”源码搭建wcqh.cninput-box”> <span> <input type=”text” placeholder=”enter recipe” onchange=”{(e)”> setquery(e.target.value)} onkeydown={handlekeydown} // add the onkeydown event handler /&gt; </span> <iosearch classname=”search-btn” onclick=”{ge源码搭建wcqh.cntrecipe}”></iosearch> </div> </div> <div ref=”{recipesectionref}” classname=”recipes”> {recipe.map((item, index) =&gt; ( <div key=”{index}” classname=”recipe”> @@##@@ <h2 classname=”label”>{item.recipe.label}</h2> 源码搭建wcqh.cn <link to={`/recipe/${item.recipe.uri.split(“_”)[1]}`}> <button classname=”button”>view recipe</button> </div> ))} </div> </div> ); }; export default home;
登录后复制
收藏夹.js

此页面显示最喜欢的食谱。

import react, {源码搭建wcqh.cn usestate, useeffect } from “react”; import { link } from “react-router-dom”; const favorites = () =&gt; { const [favorites, setfavorites] = usestate([]); useeffect(() =&gt; { const savedfavorites = json.parse(localstorage.getitem(“favori源码搭建wcqh.cntes”)) || []; setfavorites(savedfavorites); }, []); if (favorites.length === 0) { return <div>no favorite recipes found.</div>; } return ( <div classname=”favorites-page “> <div classname=”favorite-reci源码搭建wcqh.cnpes-text”> <h1>favorite recipes</h1> </div> <ul classname=”recipes”> {favorites.map((recipe) =&gt; ( <div classname=”recipe”> @@##@@ <h2 classname=”label”>{recipe.label}</h2> <link to={`/recipe/${recipe.源码搭建wcqh.cnuri.split(“_”)[1]}`}> <button classname=”button”>view recipe</button> </div> ))} </ul> </div> ); }; export default favorites;
登录后复制
recipedetail.js

此页面显示食谱。

import react, { usestate, useeffect } from “react源码搭建wcqh.cn“; import { useparams } from “react-router-dom”; const recipedetail = () =&gt; { const { id } = useparams(); // use react router to get the recipe id from the url const [recipe, setrecipe] = usestate(null); const [loading, setloading] = us源码搭建wcqh.cnestate(true); const [error, seterror] = usestate(null); const [favorites, setfavorites] = usestate([]); const api_id = “2cbb7807”; const api_key = “17222f5be3577d4980d6ee3bb57e9f00”; useeffect(() =&gt; { const fetchrecipedetai源码搭建wcqh.cnl = async () =&gt; { try { const response = await fetch( `https://api.edamam.com/api/recipes/v2/${id}?type=public&amp;app_id=${api_id}&amp;app_key=${api_key}` ); if (!response.ok) { throw new error(“network response was not ok”)源码搭建wcqh.cn; } const data = await response.json(); setrecipe(data.recipe); setloading(false); } catch (error) { seterror(“failed to fetch recipe details”); setloading(false); } }; fetchrecip源码搭建wcqh.cnedetail(); }, [id]); useeffect(() =&gt; { const savedfavorites = json.parse(localstorage.getitem(“favorites”)) || []; setfavorites(savedfavorites); }, []); const addtofavorites = () =&gt; { const updatedfavorites =源码搭建wcqh.cn […favorites, recipe]; setfavorites(updatedfavorites); localstorage.setitem(“favorites”, json.stringify(updatedfavorites)); }; const removefromfavorites = () =&gt; { const updatedfavorites = favorites.filter( (fav) =&gt; fav.源码搭建wcqh.cnuri !== recipe.uri ); setfavorites(updatedfavorites); localstorage.setitem(“favorites”, json.stringify(updatedfavorites)); }; const isfavorite = favorites.some((fav) =&gt; fav.uri === recipe?.uri); if (loading) ret源码搭建wcqh.cnurn ( <div classname=”loader-section”> <div classname=”loader”></div> </div> ); if (error) return <div>{error}</div>; return ( <div classname=”recipe-detail”> {recipe &amp;&amp; ( <div class源码搭建wcqh.cnname=”recipe-details-text”> <h1>{recipe.label}</h1> <h2>ingredients:</h2> <ul> {recipe.ingredientlines.map((ingredient, index) =&gt; ( <li key=”{index}”>{ingredient}</li> ))} </ul> <h2>instructions:</h2> 源码搭建wcqh.cn {/* note: edamam api doesnt provide instructions directly. you might need to link to the original recipe url */} <p> for detailed instructions, please visit the{” “} <a href=”%7Brecipe.url%7D” target=”_blank” rel=”noopener noreferrer”> reci源码搭建wcqh.cnpe instruction </a> </p> {isfavorite ? ( <button classname=”fav-btn” onclick=”{removefromfavorites}”>remove from favorites</button> ) : ( <button classname=”fav-btn” onclick=”{addtofavorites}”>add to favorites</button> 源码搭建wcqh.cn )} </div> <div classname=”recipe-details-img”> @@##@@ </div> &gt; )} </div> ); }; export default recipedetail;
登录后复制
联系方式.js

此页面显示联系页面。

import react, { usestate } from react; 源码搭建wcqh.cn const contact = () =&gt; { const [name, setname] = usestate(); const [email, setemail] = usestate(); const [message, setmessage] = usestate(); const [showpopup, setshowpopup] = usestate(false); const handlesubmit = (e) =&gt; { 源码搭建wcqh.cn e.preventdefault(); // prepare the contact details object const contactdetails = { name, email, message }; // save contact details to local storage const savedcontacts = json.parse(localstorage.getitem(contacts)) || []; savedcon源码搭建wcqh.cntacts.push(contactdetails); localstorage.setitem(contacts, json.stringify(savedcontacts)); // log the form data console.log(form submitted:, contactdetails); // clear form fields setname(); setemail(); setmessage()源码搭建wcqh.cn; // show popup setshowpopup(true); }; const closepopup = () =&gt; { setshowpopup(false); }; return ( <div classname=”contact”> <h1>contact us</h1> <form onsubmit=”{handlesubmit源码搭建wcqh.cn}” classname=”contact-form”> <div classname=”form-group”> <label htmlfor=”name”>name:</label> <input type=”text” id=”name” value=”{name}” onchange=”{(e)”> setname(e.target.value)} required /&gt; </div> <div classname源码搭建wcqh.cn=”form-group”> <label htmlfor=”email”>email:</label> <input type=”email” id=”email” value=”{email}” onchange=”{(e)”> setemail(e.target.value)} required /&gt; </div> <div classname=”form-group”> <label htmlfor=”messag源码搭建wcqh.cne”>message:</label> <textarea id=”message” value=”{message}” onchange=”{(e)”> setmessage(e.target.value)} required &gt;</textarea> </div> <button type=”submit”>submit</button> </form> {showpopup &amp;&amp; ( 源码搭建wcqh.cn <div classname=”popup”> <div classname=”popup-inner”> <h2>thank you!</h2> <p>your message has been submitted successfully.</p> <button onclick=”{closepopup}”>close</button> </div> </div> )} </div> 源码搭建wcqh.cn ); }; export default contact;
登录后复制
关于.js

此页面显示关于页面。

import React from react; const About = () =&gt; { return ( <div classname=”about”> <div classname=”about-main”> <h1>About Us</h1> <p> 源码搭建wcqh.cn Welcome to Recipe Finder, your go-to place for discovering delicious recipes from around the world! </p> <p> Our platform allows you to search for recipes based on your ingredients or dietary preferences. Whether youre looking for a quick meal, a healthy option源码搭建wcqh.cn, or a dish to impress your friends, we have something for everyone. </p> <p> We use the Edamam API to provide you with a vast database of recipes. You can easily find new recipes, view detailed instructions, and explore new culinary ideas. </p> 源码搭建wcqh.cn <p> <strong>Features:</strong> </p> <ul> <li>Search for recipes by ingredient, cuisine, or dietary restriction.</li> <li>Browse new and trending recipes.</li> <li>View detailed recipe instructions and ingredient lists.</li源码搭建wcqh.cn> <li>Save your favorite recipes for quick access.</li> </ul> <p> Our mission is to make cooking enjoyable and accessible. We believe that everyone should have the tools to cook great meals at home. </p> </div> </div源码搭建wcqh.cn> ); }; export default About;
登录后复制
现场演示

您可以在这里查看该项目的现场演示。

结论

食谱查找网站对于任何想要发现新的和流行食谱的人来说是一个强大的工具。通过利用 react 作为前端和 edamam api 来处理数据,我们可以提供无缝的用户体验。您可以通过添加分页、用户身份验证甚至更详细的过滤选项等功能来进一步自定义此项目。

随意尝试该项目并使其成为您自己的!

制作人员 api:毛豆 图标:react 图标 作者

abhishek源码搭建wcqh.cn gurjar 是一位专注的 web 开发人员,热衷于创建实用且功能性的 web 应用程序。在 github 上查看他的更多项目。

以上就是使用 React 构建食谱查找器网站的详细内容,更多请关注青狐资源网其它相关文章!

© 版权声明
THE END
喜欢就支持一下吧
点赞995 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容