营养计量器 – 使用React的卡路里追踪应用

营养计量器 – 使用React的卡路里追踪应用

GeeksforGeeks营养计量器 应用允许用户输入他们所消耗的食物或菜肴的名称,以及有关蛋白质、卡路里、脂肪、碳水化合物等的详细信息。用户可以跟踪他们的卡路里摄入量,并在超过卡路里限制时收到警告消息。输入项目数据和在卡片格式中保存结果的逻辑已使用JSX实现。该应用使用函数式组件和不同的hooks来管理状态。

最终输出的预览:

营养计量器 - 使用React的卡路里追踪应用

先决条件和技术:

  • ReactJS
  • CSS
  • JSX
  • 在React中使用函数组件

方法:

为了在ReactJS库中创建营养计量器,我们使用了基于函数的组件,其中我们创建了一个简单的应用程序,它接收用户输入的消耗物品,并接受卡路里、脂肪、碳水化合物等输入。一旦用户输入详细信息,数据将被保存并使用Tailwind CSS以卡片的形式呈现。卡路里的跟踪也被做到了,并对用户可见。默认情况下,卡路里限制为1000卡路里,所以如果用户超过了卡路里限制,会显示警告消息。用户还可以编辑或删除他添加的项目。

创建应用程序的步骤:

步骤1:VSCode IDE中使用下面的命令设置React项目。

npx create-react-app nutrition-app

步骤2: 通过执行以下命令导航到新创建的项目文件夹。

cd nutrition-app

步骤3: 由于我们使用Tailwind CSS进行样式设计,我们需要使用npm管理器来安装它。因此,在终端中执行以下命令来安装tailwind CSS

npm install -D tailwindcss  
npx tailwindcss init

步骤4: 执行上述命令后,将生成一个“tailwind.config.js”文件,请将以下内容粘贴到此文件中进行正确配置。

/** @type {import('tailwindcss').Config} */  
module.exports = {  
  content: [  
    "./src/**/*.{js,jsx,ts,tsx}",  
  ],  
  theme: {  
    extend: {},  
  },  
  plugins: [],  
}

步骤5: 使用下面的命令安装所需的依赖项:

npm install --save @fortawesome/react-fontawesome @fortawesome/free-solid-svg-icons font-awesome

步骤6: 现在,在src目录下创建一个名为NutritionMeter.jsx的文件,该文件将包含输入项目细节以及卡路里,脂肪等的完整代码。

项目结构:

营养计量器 - 使用React的卡路里追踪应用

package.json 中,更新的依赖项将如下所示:

{  
  "name": "nutrition-app",  
  "version": "0.1.0",  
  "private": true,  
  "dependencies": {  
    "@fortawesome/free-solid-svg-icons": "^6.4.2",  
    "@fortawesome/react-fontawesome": "^0.2.0",  
    "@testing-library/jest-dom": "^5.17.0",  
    "@testing-library/react": "^13.4.0",  
    "@testing-library/user-event": "^13.5.0",  
    "font-awesome": "^4.7.0",  
    "react": "^18.2.0",  
    "react-dom": "^18.2.0",  
    "react-scripts": "5.0.1",  
    "util": "^0.12.5",  
    "web-vitals": "^2.1.4"  
}

示例: 将以下代码插入到上面目录结构中提到的App.js和NutritionMeter.jsx文件中。

  • App.js: 该文件包含NutritionMeter.jsx代码的渲染。所有应用程序都是从此文件开始渲染的。
  • NutritionMeter.jsx: 此应用程序中的文件包含所有所需的逻辑,如从用户输入详细信息,计算卡路里,并跟踪卡路里的限制。如果卡路里超过限制,则向用户显示消息。
  • NutritionMeter.css: 通过此文件提供支持样式和吸引人的感觉。此文件中指定了所有悬停效果等。
  • index.css: 该文件包含用于样式化营养计量器应用程序的Tailwind CSS指令。
//App.js 
import React from "react"; 
import NutritionMeter from "./NutritionMeter"; 
  
function App() { 
  return ( 
    <div className="bg-gray-100 min-h-screen"> 
      <NutritionMeter /> 
    </div> 
  ); 
} 
  
export default App; 
//NutritionMeter.js File 
import React, { useState, useEffect } from "react"; 
import "./NutritionMeter.css"; 
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 
import { 
  faEdit, 
  faTrashAlt, 
  faUtensils, 
  faPlus, 
  faMinus, 
  faTimes, 
} from "@fortawesome/free-solid-svg-icons"; 
  
  
const NutritionMeter = () => { 
  const defaultItemsDisplayed = [ 
    { 
      id: 1, 
      name: "Apple", 
      calories: 52, 
      protein: 0.26, 
      carbs: 14, 
      fat: 1, 
      quantity: 1, 
    }, 
    { 
      id: 2, 
      name: "Banana", 
      calories: 89, 
      protein: 1.09, 
      carbs: 23, 
      fat: 5, 
      quantity: 1, 
    }, 
    { 
      id: 3, 
      name: "Grapes", 
      calories: 40, 
      protein: 0.2, 
      carbs: 20, 
      fat: 2, 
      quantity: 1, 
    }, 
    { 
      id: 4, 
      name: "Orange", 
      calories: 35, 
      protein: 0.15, 
      carbs: 25, 
      fat: 4, 
      quantity: 1, 
    }, 
  ]; 
  
  const [nutritionItems, setNutritionItems] = useState(defaultItemsDisplayed); 
  const [newItem, setNewItem] = useState({ 
    name: "", 
    calories: "", 
    protein: "", 
    carbs: "", 
    fat: "", 
  }); 
  
  const [editItem, setEditItem] = useState(null); 
  const [totalCalories, setTotalCalories] = useState(0); 
  const [showWarning, setShowWarning] = useState(false); 
  const [inputError, setInputError] = useState(false); 
  
  useEffect(() => { 
    const calculateTotalCalories = nutritionItems.reduce( 
      (total, item) => total + parseFloat(item.calories) * item.quantity, 
      0 
    ); 
  
    setTotalCalories(calculateTotalCalories); 
  
    if (calculateTotalCalories > 1000) { 
      setShowWarning(true); 
    } else { 
      setShowWarning(false); 
    } 
  }, [nutritionItems]); 
  
  const addNutritionItem = () => { 
    if ( 
      newItem.name && 
      newItem.calories >= 0 && 
      newItem.protein >= 0 && 
      newItem.carbs >= 0 && 
      newItem.fat >= 0 
    ) { 
      setNutritionItems([ 
        ...nutritionItems, 
        { ...newItem, id: Date.now(), quantity: 1 }, 
      ]); 
      setNewItem({ 
        name: "", 
        calories: "", 
        protein: "", 
        carbs: "", 
        fat: "", 
      }); 
      setInputError(false); 
    } else { 
      setInputError(true); 
    } 
  }; 
  
  const removeAllItems = () => { 
    setNutritionItems([]); 
  }; 
  
  const editItemFunction = (item) => { 
    setEditItem(item.id); 
    setNewItem({ ...item }); 
  }; 
  
  const updateItemFunction = () => { 
    if ( 
      newItem.name && 
      newItem.calories >= 0 && 
      newItem.protein >= 0 && 
      newItem.carbs >= 0 && 
      newItem.fat >= 0 
    ) { 
      const updatedItems = nutritionItems.map((item) => 
        item.id === newItem.id ? newItem : item 
      ); 
      setNutritionItems(updatedItems); 
      setNewItem({ 
        name: "", 
        calories: "", 
        protein: "", 
        carbs: "", 
        fat: "", 
      }); 
      setEditItem(null); 
      setInputError(false); 
    } else { 
      setInputError(true); 
    } 
  }; 
  
  const deleteItemFunction = (id) => { 
    const updatedItems = nutritionItems.filter((item) => item.id !== id); 
    setNutritionItems(updatedItems); 
  }; 
  
  const inputErrorStyle = { 
    borderColor: "red", 
  }; 
  
  const updateItemQuantity = (id, change) => { 
    const updatedItems = nutritionItems.map((item) => 
      item.id === id ? { ...item, quantity: Math.max(item.quantity + change, 1) } : item 
    ); 
    setNutritionItems(updatedItems); 
  }; 
  
  const totalProtein = () => { 
    return nutritionItems.reduce( 
      (total, item) => total + parseFloat(item.protein) * item.quantity, 
      0 
    ); 
  }; 
  
  const totalCarbs = () => { 
    return nutritionItems.reduce( 
      (total, item) => total + parseFloat(item.carbs) * item.quantity, 
      0 
    ); 
  }; 
  
  const totalFat = () => { 
    return nutritionItems.reduce( 
      (total, item) => total + parseFloat(item.fat) * item.quantity, 
      0 
    ); 
  }; 
  
  return ( 
    <div className="bg-green-200 min-h-screen"> 
      <div className="container mx-auto p-4"> 
        <h1 className="text-3xl font-semibold text-center mb-4"> 
          GeeksforGeeks Nutrition Meter 
        </h1> 
        {showWarning && ( 
          <div className="bg-red-500 text-white p-2 rounded-md text-center mb-4"> 
            <FontAwesomeIcon icon={faTimes} className="mr-2" /> 
            Total calories exceed recommended limit (1000 calories)! 
          </div> 
        )} 
        <div className="mb-4"> 
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> 
            <div> 
              <input 
                type="text"
                placeholder="Item Name"
                className={`w-full py-2 px-3 border rounded-md focus:outline-none  
                focus:ring focus:border-blue-300 { 
                  inputError && !newItem.name ? "border-red-500" : ""
                }`} 
                style={inputError && !newItem.name ? inputErrorStyle : {}} 
                value={newItem.name} 
                onChange={(e) => 
                  setNewItem({ ...newItem, name: e.target.value }) 
                } 
              /> 
            </div> 
            <div> 
              <input 
                type="number"
                placeholder="Calories"
                className={`w-full py-2 px-3 border rounded-md  
                focus:outline-none focus:ring focus:border-blue-300{ 
                  inputError && newItem.calories < 0 ? "border-red-500" : ""
                }`} 
                style={inputError && newItem.calories < 0 ? inputErrorStyle : {}} 
                value={newItem.calories} 
                onChange={(e) => 
                  setNewItem({ ...newItem, calories: e.target.value }) 
                } 
              /> 
            </div> 
            <div> 
              <input 
                type="number"
                placeholder="Protein (g)"
                className={`w-full py-2 px-3 border rounded-md focus:outline-none  
                focus:ring focus:border-blue-300 { 
                  inputError && newItem.protein<0 ? "border-red-500" : ""
                }`} 
                style={inputError && newItem.protein<0 ? inputErrorStyle : {}} 
                value={newItem.protein} 
                onChange={(e) => 
                  setNewItem({ ...newItem, protein: e.target.value }) 
                } 
              /> 
            </div> 
            <div> 
              <input 
                type="number"
                placeholder="Carbs (g)"
                className={`w-full py-2 px-3 border rounded-md focus:outline-none  
                focus:ring focus:border-blue-300{ 
                  inputError && newItem.carbs < 0 ? "border-red-500" : ""
                }`} 
                style={inputError && newItem.carbs < 0 ? inputErrorStyle : {}} 
                value={newItem.carbs} 
                onChange={(e) => 
                  setNewItem({ ...newItem, carbs: e.target.value }) 
                } 
              /> 
            </div> 
            <div> 
              <input 
                type="number"
                placeholder="Fat (g)"
                className={`w-full py-2 px-3 border rounded-md focus:outline-none  
                focus:ring focus:border-blue-300 ${ 
                  inputError && newItem.fat < 0 ? "border-red-500" : ""
                }`} 
                style={inputError && newItem.fat < 0 ? inputErrorStyle : {}} 
                value={newItem.fat} 
                onChange={(e) => 
                  setNewItem({ ...newItem, fat: e.target.value }) 
                } 
              /> 
            </div> 
            <div className="col-span-2 sm:col-span-1"></div> 
              
          </div> 
          <div className="mt-3 flex justify-between"> 
                
              {editItem ? ( 
                <button 
                  className="bg-blue-500 text-white p-3 rounded-md hover:bg-blue-600 mb-4  
                  font-semibold focus:outline-none text-xs"
                  onClick={updateItemFunction} 
                > 
                  Update Item 
                </button> 
              ) : ( 
                <button 
                  className="bg-green-600 text-white p-3 rounded-md hover:bg-green-700 mb-4  
                  font-semibold focus:outline-none text-xs"
                  onClick={addNutritionItem} 
                > 
                  Add Item 
                </button> 
              )} 
              <button 
                className="bg-red-600 text-white p-3 rounded-md font-semibold mb-4 hover:bg-red-700  
                focus:outline-none text-xs"
                onClick={removeAllItems} 
              > 
                Clear All 
              </button> 
            </div> 
        </div> 
  
        <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2"> 
          {nutritionItems.map((item) => ( 
            <div 
              key={item.id} 
              className="bg-white p-4 rounded-md shadow-md border-2 border-blue-400  
              hover:border-blue-500 hover:shadow-lg transition transform hover:scale-105"
            > 
              <h2 className="text-lg font-semibold text-gray-800">{item.name}</h2> 
              <ul className="mt-3"> 
                <li>Calories: {item.calories * item.quantity}</li> 
                <li>Protein: {item.protein * item.quantity}g</li> 
                <li>Carbs: {item.carbs * item.quantity}g</li> 
                <li>Fat: {item.fat * item.quantity}g</li> 
                <li className="flex items-center mt-2"> 
                  <button 
                    className="bg-green-500 text-white hover:bg-green-600 p-2 rounded-md font-semibol"
                    onClick={() => updateItemQuantity(item.id, 1)} 
                  > 
                    <FontAwesomeIcon icon={faPlus} /> 
                  </button> 
                  <span className="mx-2">{item.quantity}</span> 
                  <button 
                    className="bg-red-500 text-white hover:bg-red-600 p-2 rounded-md font-semibol"
                    onClick={() => updateItemQuantity(item.id, -1)} 
                  > 
                    <FontAwesomeIcon icon={faMinus} /> 
                  </button> 
                </li> 
              </ul> 
              <div className="mt-3 flex justify-between"> 
                <button 
                  className="bg-blue-500 text-white pd-2 rounded-md hover:bg-blue-600  
                  font-semibold focus:outline-none text-xs"
                  onClick={() => editItemFunction(item)} 
                > 
                  <FontAwesomeIcon icon={faEdit} /> Edit 
                </button> 
                <button 
                  className="bg-red-500 text-white pd-2 rounded-md hover:bg-red-600  
                  font-semibold focus:outline-none text-xs"
                  onClick={() => deleteItemFunction(item.id)} 
                > 
                  <FontAwesomeIcon icon={faTrashAlt} /> Delete 
                </button> 
              </div> 
            </div> 
          ))} 
        </div> 
        <div className="mt-8 text-center"> 
          <p className="text-xl font-semibold"> 
            Total Calories: {totalCalories}{" "} 
            <span id="nutrition-icon"> 
              <FontAwesomeIcon icon={faUtensils} size="lg" /> 
            </span> 
          </p> 
          <p className="text-xl font-semibold"> 
            Total Protein: {totalProtein()}g 
          </p> 
          <p className="text-xl font-semibold"> 
            Total Carbs: {totalCarbs()}g 
          </p> 
          <p className="text-xl font-semibold">Total Fat: {totalFat()}g</p> 
        </div> 
      </div> 
    </div> 
  ); 
}; 
  
export default NutritionMeter;

CSS

/*NutritionMeter.css File*/
body { 
  font-family: Arial, sans-serif; 
  background-color: #f3f3f3; 
  margin: 0; 
  padding: 0; 
  color: #333; 
} 
  
.container { 
  max-width: 800px; 
  margin: 0 auto; 
  padding: 20px; 
  background-color: #fff; 
  border-radius: 8px; 
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 
  transition: box-shadow 0.3s, transform 0.3s; 
} 
  
.text-center { 
  text-align: center; 
} 
  
  
.warning { 
  background-color: #ff6b6b; 
  color: white; 
  padding: 10px; 
  display: flex; 
  align-items: center; 
  border-radius: 8px; 
  margin-bottom: 20px; 
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); 
  transition: background-color 0.3s; 
} 
  
.warning svg { 
  margin-right: 10px; 
} 
  
  
.clear-button { 
  background-color: #e74c3c; 
  color: white; 
  border: none; 
  padding: 10px 20px; 
  border-radius: 8px; 
  cursor: pointer; 
  margin-bottom: 20px; 
  display: block; 
  width: 100%; 
  text-align: center; 
  font-weight: bold; 
  transition: background-color 0.3s; 
} 
  
.clear-button:hover { 
  background-color: #c0392b; 
} 
#nutrition-icon { 
  color: #3498db; 
  margin-left: 10px; 
} 
  
button { 
  cursor: pointer; 
  width: 48%; 
  padding: 12px 0; 
  background-color: #3498db; 
  color: white; 
  border: none; 
  border-radius: 8px; 
  transition: background-color 0.3s; 
  font-weight: bold; 
} 
  
button.edit-button { 
  margin-right:5%; 
} 
  
button.delete-button { 
  margin-left: 5%; 
} 
  
button:hover { 
  background-color: #2980b9; 
} 
  
  
.error-message { 
  color: #e74c3c; 
  font-size: 14px; 
  margin-top: 5px; 
} 
  
  
@keyframes float { 
  0% { 
    transform: translateY(0); 
  } 
  50% { 
    transform: translateY(-5px); 
  } 
  100% { 
    transform: translateY(0); 
  } 
} 
.gradient-background { 
  background: linear-gradient( 
    to right, 
    #3498db, 
    #6dd5fa
  ); 
} 

CSS

/* index.css File */
@tailwind base; 
@tailwind components; 
@tailwind utilities;

运行该应用程序的步骤:

步骤1 。在终端中执行以下命令来运行应用程序。

npm start

步骤2 . 打开像Chrome或Firefox这样的网络浏览器,并在地址栏中输入以下URL。

http://localhost:3000/

输出:

营养计量器 - 使用React的卡路里追踪应用

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程