与GPT创建react外卖应用

创建一个基本的外卖服务的应用。首先,需要安装React和create-react-app。

创建应用:
在终端中运行以下命令来创建应用:
npx create-react-app food-delivery-app
安装所需的依赖:
进入应用目录并运行以下命令安装所需的依赖:
cd food-delivery-app npm install axios react-router-dom react-icons
axios:用于发送HTTP请求。
react-router-dom:用于实现路由。
react-icons:用于添加图标。
创建组件:
在src目录下创建以下文件:
App.js
Header.js
Footer.js
Menu.js
MenuItem.js
Checkout.js
这些组件将构成我们外卖服务的基本结构和功能。

实现Header:
在Header.js中添加以下代码:

import { Link } from "react-router-dom";
import { FiShoppingCart } from "react-icons/fi";

const Header = () => {
  return (
    <header className="header">
      <h1>
        <Link to="/">Food Delivery App</Link>
      </h1>
      <nav>
        <ul>
          <li>
            <Link to="/">Menu</Link>
          </li>
          <li>
            <Link to="/checkout">
              <FiShoppingCart />
              <span className="count">0</span>
            </Link>
          </li>
        </ul>
      </nav>
    </header>
  );
};

export default Header;

这里使用了Link组件实现路由导航,FiShoppingCart组件用于显示购物车图标,count组件用于显示购物车中的数量。
实现Footer:
在Footer.js中添加以下代码:

import React from "react";

const Footer = () => {
  return (
    <footer className="footer">
      <p>&copy; 2021 Food Delivery App. All Rights Reserved.</p>
    </footer>
  );
};

export default Footer;

实现Menu:
在Menu.js中添加以下代码:

import React, { useState, useEffect } from "react";
import axios from "axios";
import MenuItem from "./MenuItem";
import CartItem from "./CartItem";
import Checkout from "./Checkout";

const Menu = () => {
  const [menuItems, setMenuItems] = useState([]);
  const [cartItems, setCartItems] = useState([]);

  useEffect(() => {
    axios
      .get("http://localhost:3000/menuItems")
      .then((response) => {
        setMenuItems(response.data);
      })
      .catch((error) => {
        console.log(error);
      });
    const dishes = [
      { id: 1, name: '菜品 A', price: 10, description: '菜品 AA' },
      { id: 2, name: '菜品 B', price: 15, description: '菜品 BA' },
      { id: 3, name: '菜品 C', price: 12, description: '菜品 CA' },
    ]
    setMenuItems(dishes)
  }, []);

  const addToCart = (item) => {
    const index = cartItems.findIndex((cartItem) => cartItem.id === item.id);
    if (index === -1) {
      setCartItems([...cartItems, item]);
    } else {
      const newCartItems = [...cartItems];
      newCartItems[index] = {
        ...newCartItems[index],
        quantity: newCartItems[index].quantity + item.quantity,
      };
      setCartItems(newCartItems);
    }
  };

  const removeFromCart = (item) => {
    const index = cartItems.findIndex((cartItem) => cartItem.id === item.id);
    if (index === -1) {
      return;
    } else {
      const newCartItems = [...cartItems];
      if (newCartItems[index].quantity === 1) {
        newCartItems.splice(index, 1);
      } else {
        newCartItems[index] = {
          ...newCartItems[index],
          quantity: newCartItems[index].quantity - 1,
        };
      }
      setCartItems(newCartItems);
    }
  };

  return (
    <main className="menu">
      <h2>Menu</h2>
      <ul>
        {menuItems.map((menuItem) => (
          <MenuItem
            key={menuItem.id}
            menuItem={menuItem}
            addToCart={addToCart}
          />
        ))}
      </ul>
      <hr />
      <div className="cart">
        <h3>Cart</h3>
        <ul>
          {cartItems.map((item) => (
            <CartItem
              key={item.id}
              item={item}
              addToCart={addToCart}
              removeFromCart={removeFromCart}
            />
          ))}
        </ul>
        {cartItems.length === 0 ? (
          <p>Your cart is empty.</p>
        ) : (
          <Checkout
            cartItems={cartItems}
            setCartItems={setCartItems}
          />
        )}
      </div>
    </main>
  );
};

export default Menu;

这里使用了useState和useEffect hooks来获取菜单项的数据。MenuItem组件将用于渲染每个菜单项。

实现MenuItem:
在MenuItem.js中添加以下代码:

import React, { useState } from "react";

const MenuItem = ({ menuItem, addToCart }) => {
  const [quantity, setQuantity] = useState(1);

  const handleAddToCart = () => {
    const item = {
      id: menuItem.id,
      name: menuItem.name,
      price: menuItem.price,
      quantity: quantity,
    };
    addToCart(item);
  };

  const handleQuantity = (event) => {
    setQuantity(Number(event.target.value));
  };

  return (
    <li className="menu-item">
      <h3>{menuItem.name}</h3>
      <p>{menuItem.description}</p>
      <p className="price">${menuItem.price}</p>
      <input
        type="number"
        value={quantity}
        onChange={handleQuantity}
        min="1"
        max="10"
      />
      <button onClick={handleAddToCart}>Add to Cart</button>
    </li>
  );
};

export default MenuItem;

实现Checkout:
在Checkout.js中添加以下代码:

import React, { useState, useEffect } from "react";

const Checkout = ({ cartItems, setCartItems }) => {
  const [total, setTotal] = useState(
    cartItems && cartItems.length ? calculateTotal(cartItems) : 0
  );

  // 计算总价
  function calculateTotal (items) {
    return items.reduce((acc, item) => acc + item.price * item.quantity, 0);
  }

  // 当购物车项更改时计算总价
  useEffect(() => {
    setTotal(cartItems && cartItems.length ? calculateTotal(cartItems) : 0);
  }, [cartItems]);

  // 将商品添加到购物车
  const handleAddToCart = (item) => {
    const index = cartItems.findIndex((cartItem) => cartItem.id === item.id);
    if (index === -1) {
      setCartItems([...cartItems, item]);
    } else {
      const newCartItems = [...cartItems];
      newCartItems[index] = {
        ...newCartItems[index],
        quantity: newCartItems[index].quantity + item.quantity,
      };
      setCartItems(newCartItems);
    }
    setTotal(calculateTotal([...cartItems, item]));
  };

  // 从购物车中删除商品
  const handleRemoveFromCart = (item) => {
    const index = cartItems.findIndex((cartItem) => cartItem.id === item.id);
    if (index === -1) {
      return;
    } else {
      const newCartItems = [...cartItems];
      if (newCartItems[index].quantity === 1) {
        newCartItems.splice(index, 1);
      } else {
        newCartItems[index] = {
          ...newCartItems[index],
          quantity: newCartItems[index].quantity - 1,
        };
      }
      setCartItems(newCartItems);
      setTotal(calculateTotal(newCartItems));
    }
  };

  return (
    <main className="checkout">
      <h2>Checkout</h2>
      <ul className="cart-items">
        {cartItems &&
          cartItems.map((item) => (
            <li key={item.id}>
              <span>{item.name}</span>
              <span>{item.price.toFixed(2)}</span>
              <div className="quantity">
                <button onClick={() => handleRemoveFromCart(item)}>-</button>
                <span>{item.quantity}</span>
                <button onClick={() => handleAddToCart(item)}>+</button>
              </div>
              <span>{(item.price * item.quantity).toFixed(2)}</span>
            </li>
          ))}
      </ul>
      <div className="total">
        <span>Total:</span>
        <span>${total.toFixed(2)}</span>
      </div>
    </main>
  );
};

export default Checkout;

这里创建了一个简单的结账页面,其包括表格来显示购物车中的商品以及购物车的总价。
CartItem.js:

import React from "react";

const CartItem = ({ item, addToCart, removeFromCart }) => {
  const handleAdd = () => {
    addToCart(item);
  };

  const handleRemove = () => {
    removeFromCart(item);
  };

  return (
    <li>
      <span>{item.name}</span>
      <span>{item.price.toFixed(2)}</span>
      <div className="quantity">
        <button onClick={handleRemove}>-</button>
        <span>{item.quantity}</span>
        <button onClick={handleAdd}>+</button>
      </div>
      <span>{(item.price * item.quantity).toFixed(2)}</span>
    </li>
  );
};

export default CartItem;

实现App:
在App.js中添加以下代码:

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Header from "./Header";
import Footer from "./Footer";
import Menu from "./Menu";
import Checkout from "./Checkout";
import "./App.css";

const App = () => {
  return (
    <>
      <Router>
        <Header />
        <Routes>
          <Route path="/" element={<Menu />} />
          <Route path="/checkout" element={<Checkout />} />
        </Routes>
        <Footer />
      </Router>
    </>
  );
};

export default App;

这里使用了BrowserRouter来包含应用程序的路由,Switch用于包含所有路由对象,并渲染与所选路由匹配的首个对象。Header和Footer组件固定用于页面头和底部。Menu和Checkout组件用于渲染菜单和结账页面。*如果您正在使用React Router v6,那么Switch已经被移除了,你应该改用Routes。

运行应用程序:
在终端中运行以下命令来启动应用程序:
npm start
在浏览器中输入http://localhost:3000,即可进入应用程序。您应该能够在Menu页面看到所有菜单项,以及在Checkout页面看到您所选购的商品和总价。

这只是一个基本的实现,但是您可以根据需要进行扩展和增强。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容