创建一个基本的外卖服务的应用。首先,需要安装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>© 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页面看到您所选购的商品和总价。
这只是一个基本的实现,但是您可以根据需要进行扩展和增强。