使用 React 构建食谱查找器网站
“纵有疾风来,人生不言弃”,这句话送给正在学习文章的朋友们,也希望在阅读本文《使用 React 构建食谱查找器网站》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新文章相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!
介绍
在本博客中,我们将使用 react 构建一个食谱查找网站。该应用程序允许用户搜索他们最喜欢的食谱,查看趋势或新食谱,并保存他们最喜欢的食谱。我们将利用 edamam api 获取实时食谱数据并将其动态显示在网站上。
项目概况
食谱查找器允许用户:
- 按名称搜索食谱。
- 查看趋势和新添加的食谱。
- 查看各个食谱的详细信息。
- 将食谱添加到收藏夹列表并使用 localstorage 保存数据。
特征
- 搜索功能:用户可以通过输入查询来搜索食谱。
- 热门食谱:显示来自 api 的当前热门食谱。
- 新菜谱:显示来自 api 的最新菜谱。
- 食谱详细信息:显示有关所选食谱的详细信息。
- 收藏夹:允许用户将食谱添加到收藏夹列表,该列表保存在本地。
使用的技术
- react:用于构建用户界面。
- react router:用于不同页面之间的导航。
- edamam api:用于获取食谱。
- css:用于设计应用程序的样式。
项目结构
src/ │ ├── components/ │ └── navbar.js │ ├── pages/ │ ├── home.js │ ├── about.js │ ├── trending.js │ ├── newrecipe.js │ ├── recipedetail.js │ ├── contact.js │ └── favorites.js │ ├── app.js ├── index.js ├── app.css └── index.css
安装
要在本地运行此项目,请按照以下步骤操作:
- 克隆存储库:
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。
用法
应用程序.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 trending 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 = () => { return ( <>} /> } /> } /> } /> } /> } /> } /> } /> > ); }; export default app;made with ❤️ by abhishek gurjar
主页.js
这是用户可以使用 edamam api 搜索食谱的主页。
import react, { usestate, useref, useeffect } from "react"; import { iosearch } from "react-icons/io5"; import { link } from "react-router-dom"; const home = () => { const [query, setquery] = usestate(""); const [recipe, setrecipe] = usestate([]); const recipesectionref = useref(null); const api_id = "2cbb7807"; const api_key = "17222f5be3577d4980d6ee3bb57e9f00"; const getrecipe = async () => { if (!query) return; // add a check to ensure the query is not empty const response = await fetch( `https://api.edamam.com/search?q=${query}&app_id=${api_id}&app_key=${api_key}` ); 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(() => { if (recipe.length > 0 && recipesectionref.current) { recipesectionref.current.scrollintoview({ behavior: "smooth" }); } }, [recipe]); // handle key down event to trigger getrecipe on enter key press const handlekeydown = (e) => { if (e.key === "enter") { getrecipe(); } }; return (); }; export default home;find your favourite recipe
setquery(e.target.value)} onkeydown={handlekeydown} // add the onkeydown event handler /> {recipe.map((item, index) => ())}![]()
{item.recipe.label}
trending.js
此页面获取并显示趋势食谱。
import react, { usestate, useeffect } from "react"; import { link } from "react-router-dom"; const trending = () => { const [trendingrecipes, settrendingrecipes] = usestate([]); const [loading, setloading] = usestate(true); const [error, seterror] = usestate(null); const api_id = "2cbb7807"; const api_key = "17222f5be3577d4980d6ee3bb57e9f00"; useeffect(() => { const fetchtrendingrecipes = async () => { try { const response = await fetch( `https://api.edamam.com/api/recipes/v2?type=public&q=trending&app_id=${api_id}&app_key=${api_key}` ); if (!response.ok) { throw new error("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); } }; fetchtrendingrecipes(); }, []); if (loading) return (); if (error) return{error}; return (); }; export default trending;trending recipes
{trendingrecipes.map((item, index) => ())}![]()
{item.recipe.label}
新菜谱.js
此页面获取新食谱并显示新食谱。
import react, { usestate, useeffect } from "react"; import { link } from "react-router-dom"; const newrecipe = () => { const [newrecipes, setnewrecipes] = usestate([]); const [loading, setloading] = usestate(true); const [error, seterror] = usestate(null); const api_id = "2cbb7807"; const api_key = "17222f5be3577d4980d6ee3bb57e9f00"; useeffect(() => { const fetchnewrecipes = async () => { try { const response = await fetch( `https://api.edamam.com/api/recipes/v2?type=public&q=new&app_id=${api_id}&app_key=${api_key}` ); if (!response.ok) { 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); } }; fetchnewrecipes(); }, []); if (loading) return (); if (error) return{error}; return (); }; export default newrecipe;new recipes
{newrecipes.map((item, index) => ())}![]()
{item.recipe.label}
主页.js
此页面获取并显示主页和搜索的食谱。
import react, { usestate, useref, useeffect } from "react"; import { iosearch } from "react-icons/io5"; import { link } from "react-router-dom"; const home = () => { const [query, setquery] = usestate(""); const [recipe, setrecipe] = usestate([]); const recipesectionref = useref(null); const api_id = "2cbb7807"; const api_key = "17222f5be3577d4980d6ee3bb57e9f00"; const getrecipe = async () => { if (!query) return; // add a check to ensure the query is not empty const response = await fetch( `https://api.edamam.com/search?q=${query}&app_id=${api_id}&app_key=${api_key}` ); 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(() => { if (recipe.length > 0 && recipesectionref.current) { recipesectionref.current.scrollintoview({ behavior: "smooth" }); } }, [recipe]); // handle key down event to trigger getrecipe on enter key press const handlekeydown = (e) => { if (e.key === "enter") { getrecipe(); } }; return (); }; export default home;find your favourite recipe
setquery(e.target.value)} onkeydown={handlekeydown} // add the onkeydown event handler /> {recipe.map((item, index) => ())}![]()
{item.recipe.label}
收藏夹.js
此页面显示最喜欢的食谱。
import react, { usestate, useeffect } from "react"; import { link } from "react-router-dom"; const favorites = () => { const [favorites, setfavorites] = usestate([]); useeffect(() => { const savedfavorites = json.parse(localstorage.getitem("favorites")) || []; setfavorites(savedfavorites); }, []); if (favorites.length === 0) { returnno favorite recipes found.; } return (); }; export default favorites;favorite recipes
{favorites.map((recipe) => (
))}![]()
{recipe.label}
recipedetail.js
此页面显示食谱。
import react, { usestate, useeffect } from "react"; import { useparams } from "react-router-dom"; const recipedetail = () => { const { id } = useparams(); // use react router to get the recipe id from the url const [recipe, setrecipe] = usestate(null); const [loading, setloading] = usestate(true); const [error, seterror] = usestate(null); const [favorites, setfavorites] = usestate([]); const api_id = "2cbb7807"; const api_key = "17222f5be3577d4980d6ee3bb57e9f00"; useeffect(() => { const fetchrecipedetail = async () => { try { const response = await fetch( `https://api.edamam.com/api/recipes/v2/${id}?type=public&app_id=${api_id}&app_key=${api_key}` ); if (!response.ok) { throw new error("network response was not ok"); } const data = await response.json(); setrecipe(data.recipe); setloading(false); } catch (error) { seterror("failed to fetch recipe details"); setloading(false); } }; fetchrecipedetail(); }, [id]); useeffect(() => { const savedfavorites = json.parse(localstorage.getitem("favorites")) || []; setfavorites(savedfavorites); }, []); const addtofavorites = () => { const updatedfavorites = [...favorites, recipe]; setfavorites(updatedfavorites); localstorage.setitem("favorites", json.stringify(updatedfavorites)); }; const removefromfavorites = () => { const updatedfavorites = favorites.filter( (fav) => fav.uri !== recipe.uri ); setfavorites(updatedfavorites); localstorage.setitem("favorites", json.stringify(updatedfavorites)); }; const isfavorite = favorites.some((fav) => fav.uri === recipe?.uri); if (loading) return (); if (error) return{error}; return ({recipe && ( <>); }; export default recipedetail;{recipe.label}
ingredients:
{recipe.ingredientlines.map((ingredient, index) => (
- {ingredient}
))}instructions:
{/* note: edamam api doesn't provide instructions directly. you might need to link to the original recipe url */}for detailed instructions, please visit the{" "} recipe instruction
{isfavorite ? ( ) : ( )}> )}![]()
联系方式.js
此页面显示联系页面。
import react, { usestate } from 'react'; const contact = () => { const [name, setname] = usestate(''); const [email, setemail] = usestate(''); const [message, setmessage] = usestate(''); const [showpopup, setshowpopup] = usestate(false); const handlesubmit = (e) => { 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')) || []; savedcontacts.push(contactdetails); localstorage.setitem('contacts', json.stringify(savedcontacts)); // log the form data console.log('form submitted:', contactdetails); // clear form fields setname(''); setemail(''); setmessage(''); // show popup setshowpopup(true); }; const closepopup = () => { setshowpopup(false); }; return (); }; export default contact;contact us
{showpopup && ()}thank you!
your message has been submitted successfully.
关于.js
此页面显示关于页面。
import React from 'react'; const About = () => { return (); }; export default About;About Us
Welcome to Recipe Finder, your go-to place for discovering delicious recipes from around the world!
Our platform allows you to search for recipes based on your ingredients or dietary preferences. Whether you're looking for a quick meal, a healthy option, or a dish to impress your friends, we have something for everyone.
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.
Features:
- Search for recipes by ingredient, cuisine, or dietary restriction.
- Browse new and trending recipes.
- View detailed recipe instructions and ingredient lists.
- Save your favorite recipes for quick access.
Our mission is to make cooking enjoyable and accessible. We believe that everyone should have the tools to cook great meals at home.
现场演示
您可以在这里查看该项目的现场演示。
结论
食谱查找网站对于任何想要发现新的和流行食谱的人来说是一个强大的工具。通过利用 react 作为前端和 edamam api 来处理数据,我们可以提供无缝的用户体验。您可以通过添加分页、用户身份验证甚至更详细的过滤选项等功能来进一步自定义此项目。
随意尝试该项目并使其成为您自己的!
制作人员
- api:毛豆
- 图标:react 图标
作者
abhishek gurjar 是一位专注的 web 开发人员,热衷于创建实用且功能性的 web 应用程序。在 github 上查看他的更多项目。
终于介绍完啦!小伙伴们,这篇关于《使用 React 构建食谱查找器网站》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

- 上一篇
- win11用户名怎么更改 win11用户名更改方法

- 下一篇
- (更新:机场客服回应)继昨晚之后,天津滨海机场今天晚间再次出现多架航班盘旋
-
- 文章 · 前端 | 6小时前 | 资源管理 防抖 懒加载 requestAnimationFrame 节流
- JavaScript游戏性能优化技巧全集
- 349浏览 收藏
-
- 文章 · 前端 | 7小时前 |
- JavaScript错误边界终极实现指南
- 409浏览 收藏
-
- 文章 · 前端 | 7小时前 | TypeScript React props PropTypes useCallback
- JavaScript组件属性传递的实用技巧
- 394浏览 收藏
-
- 文章 · 前端 | 7小时前 |
- JavaScript移除事件监听器的实用技巧
- 360浏览 收藏
-
- 文章 · 前端 | 7小时前 |
- JavaScript本地存储(localStorage)玩法终极攻略
- 238浏览 收藏
-
- 文章 · 前端 | 9小时前 | html CSS JavaScript 用户体验 Tooltip
- JavaScript中Tooltip提示框的实现方法
- 388浏览 收藏
-
- 文章 · 前端 | 10小时前 |
- JavaScript数组求和的实用技巧
- 446浏览 收藏
-
- 文章 · 前端 | 11小时前 | JavaScript 模块化 策略模式 折扣策略 动态选择
- JavaScript策略模式实战攻略
- 236浏览 收藏
-
- 文章 · 前端 | 12小时前 |
- JavaScript中如何用try-catch捕捉错误?
- 322浏览 收藏
-
- 文章 · 前端 | 12小时前 |
- 巧用JavaScript回调函数,提升代码效率技巧
- 347浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 笔灵AI生成答辩PPT
- 探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
- 15次使用
-
- 知网AIGC检测服务系统
- 知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
- 24次使用
-
- AIGC检测-Aibiye
- AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
- 30次使用
-
- 易笔AI论文
- 易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
- 40次使用
-
- 笔启AI论文写作平台
- 笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
- 35次使用
-
- 优化用户界面体验的秘密武器:CSS开发项目经验大揭秘
- 2023-11-03 501浏览
-
- 使用微信小程序实现图片轮播特效
- 2023-11-21 501浏览
-
- 解析sessionStorage的存储能力与限制
- 2024-01-11 501浏览
-
- 探索冒泡活动对于团队合作的推动力
- 2024-01-13 501浏览
-
- UI设计中为何选择绝对定位的智慧之道
- 2024-02-03 501浏览