使用 Context API 管理购物车状态
我首先将您的购物车状态和持久性隔离到本地存储到反应上下文提供程序。上下文可以为应用程序的其余部分提供购物车状态和操作调度程序,并在使用效果更新状态时将状态持久化到 localStorage。这将所有状态管理与应用程序分离,应用程序只需要使用上下文来访问购物车状态并调度操作来更新它。
import React, { createContext, useEffect, useReducer } from "react";
import { cartReducer, initializer } from "../cartReducer";
export const CartContext = createContext();
export const CartProvider = ({ children }) => {
const [cart, dispatch] = useReducer(cartReducer, [], initializer);
useEffect(() => {
localStorage.setItem("localCart", JSON.stringify(cart));
}, [cart]);
return (
<CartContext.Provider
value={{
cart,
dispatch
}}
>
{children}
</CartContext.Provider>
);
};
将应用程序包装在 index.js 中的 CartProvider 中
<CartProvider>
<App />
</CartProvider>
完成应用程序的其余部分
在cartReducer 中细化reducer,并导出初始化函数和action creators。
const initialState = [];
export const initializer = (initialValue = initialState) =>
JSON.parse(localStorage.getItem("localCart")) || initialValue;
export const cartReducer = (state, action) => {
switch (action.type) {
case "ADD_TO_CART":
return state.find((item) => item.name === action.item.name)
? state.map((item) =>
item.name === action.item.name
? {
...item,
quantity: item.quantity + 1
}
: item
)
: [...state, { ...action.item, quantity: 1 }];
case "REMOVE_FROM_CART":
return state.filter((item) => item.name !== action.item.name);
case "DECREMENT_QUANTITY":
// if quantity is 1 remove from cart, otherwise decrement quantity
return state.find((item) => item.name === action.item.name)?.quantity ===
1
? state.filter((item) => item.name !== action.item.name)
: state.map((item) =>
item.name === action.item.name
? {
...item,
quantity: item.quantity - 1
}
: item
);
case "CLEAR_CART":
return initialState;
default:
return state;
}
};
export const addToCart = (item) => ({
type: "ADD_TO_CART",
item
});
export const decrementItemQuantity = (item) => ({
type: "DECREMENT_QUANTITY",
item
});
export const removeFromCart = (item) => ({
type: "REMOVE_FROM_CART",
item
});
export const clearCart = () => ({
type: "CLEAR_CART"
});
在Product.js 中,通过useContext 挂钩获取购物车上下文并调度addToCart 操作
import React, { useContext, useState } from "react";
import { CartContext } from "../CartProvider";
import { addToCart } from "../cartReducer";
const Item = () => {
const { dispatch } = useContext(CartContext);
...
const addToCartHandler = (product) => {
dispatch(addToCart(product));
};
...
return (
...
);
};
CartItem.js 获取并使用购物车上下文来调度操作以减少数量或移除商品。
import React, { useContext } from "react";
import { CartContext } from "../CartProvider";
import { decrementItemQuantity, removeFromCart } from "../cartReducer";
const CartItem = () => {
const { cart, dispatch } = useContext(CartContext);
const removeFromCartHandler = (itemToRemove) =>
dispatch(removeFromCart(itemToRemove));
const decrementQuantity = (item) => dispatch(decrementItemQuantity(item));
return (
<>
{cart.map((item, idx) => (
<div className="cartItem" key={idx}>
<h3>{item.name}</h3>
<h5>
Quantity: {item.quantity}{" "}
<span>
<button type="button" onClick={() => decrementQuantity(item)}>
<i>Decrement</i>
</button>
</span>
</h5>
<h5>Cost: {item.cost} </h5>
<button onClick={() => removeFromCartHandler(item)}>Remove</button>
</div>
))}
</>
);
};
App.js 通过上下文挂钩获取购物车状态和调度程序,并更新商品总数和价格逻辑以考虑商品数量。
import { CartContext } from "./CartProvider";
import { clearCart } from "./cartReducer";
export default function App() {
const { cart, dispatch } = useContext(CartContext);
const clearCartHandler = () => {
dispatch(clearCart());
};
const { items, total } = cart.reduce(
({ items, total }, { cost, quantity }) => ({
items: items + quantity,
total: total + quantity * cost
}),
{ items: 0, total: 0 }
);
return (
<div className="App">
<h1>Emoji Store</h1>
<div className="products">
<Product />
</div>
<div className="cart">
<CartItem />
</div>
<h3>
Items in Cart: {items} | Total Cost: ${total.toFixed(2)}
</h3>
<button onClick={clearCartHandler}>Clear Cart</button>
</div>
);
}