Cách tạo Giỏ hàng trong Next.js với Ngữ cảnh và useReducer

Giỏ hàng là một phần thiết yếu của bất kỳ trang web thương mại điện tử nào. Nó cho phép khách hàng lưu trữ và mua sản phẩm.
Trong ứng dụng thương mại điện tử Next.js, bạn có thể sử dụng API ngữ cảnh và hook useReducer để tạo giỏ hàng. API bối cảnh đơn giản hóa việc chia sẻ dữ liệu giỏ hàng giữa các thành phần trong khi useReducer xử lý trạng thái giỏ hàng.
Mục Lục
Tạo trang sản phẩm
Trong thư mục pages, tạo một tệp mới có tên Product.jsx để hiển thị một sản phẩm.
export default function Product({id, name, price}) {
return (
<div>
<p>{name}</p>
<p>{price}</p>
<button>Add to Cart</button>
</div>
)
}
Thành phần sản phẩm chấp nhận ID, tên và giá của sản phẩm và hiển thị sản phẩm đó. Nó cũng có nút “Thêm vào giỏ hàng”.
Khi một sản phẩm đã được thêm vào giỏ hàng, nút này sẽ chuyển sang nút “xóa khỏi giỏ hàng” và nếu một sản phẩm không có trong giỏ hàng, trang sẽ hiển thị nút “Thêm vào giỏ hàng”.
Để triển khai chức năng này, bạn cần theo dõi các mặt hàng trong giỏ hàng bằng cách sử dụng API ngữ cảnh và hook useReducer.
Tạo giỏ hàng bằng API ngữ cảnh
API bối cảnh cho phép bạn chia sẻ dữ liệu giữa các thành phần khác nhau mà không cần phải chuyển các đạo cụ theo cách thủ công từ cấp độ gốc sang cấp độ con. Các thành phần này có thể là thanh điều hướng, trang chi tiết sản phẩm hoặc trang thanh toán.
Tạo một tệp mới có tên là cartContext.js trong một thư mục có tên là ngữ cảnh và tạo ngữ cảnh.
import { createContext } from "react";export const CartContext = createContext({
items: [],
});
CartContext lấy một mảng các mục làm giá trị mặc định.
Tiếp theo, tạo nhà cung cấp ngữ cảnh. Trình cung cấp ngữ cảnh cho phép các thành phần sử dụng ngữ cảnh đăng ký thay đổi ngữ cảnh.
Trong một chức năng mới có tên là cartProvider, hãy thêm vào như sau:
export const CartProvider = ({ children }) => {
return <CartContext.Provider>{children}</CartContext.Provider>;
};
Để theo dõi các mặt hàng trong giỏ hàng, bạn sẽ sử dụng hook useReducer.
Móc useReducer hoạt động giống như móc useState ngoại trừ nó giúp quản lý logic trạng thái phức tạp hơn. Nó chấp nhận một hàm giảm tốc và trạng thái ban đầu. Nó trả về trạng thái hiện tại và một hàm điều phối chuyển một hành động cho hàm giảm tốc.
Tạo một chức năng mới gọi là CartReducer và thêm bộ giảm tốc.
const cartReducer = (state, action) => {
const { type, payload } = action; switch (type) {
case "ADD":
return {
...state,
items: payload.items,
};
case "REMOVE":
return {
...state,
items: payload.items,
};
default:
throw new Error("No case for that type");
}
};
Hàm giảm tốc bao gồm một câu lệnh chuyển đổi cập nhật trạng thái tùy thuộc vào loại hành động. Chức năng rút gọn giỏ hàng có các hành động “THÊM” và “XÓA” lần lượt thêm vào giỏ hàng và xóa khỏi giỏ hàng.
Sau khi tạo hàm giảm tốc, hãy sử dụng nó trong hook useReducer. Bắt đầu bằng cách tạo chức năng CartProvider. Đây là chức năng sẽ cung cấp bối cảnh cho các thành phần khác.
export const CartProvider = ({children}) => {
return <CartContext.Provider>{children}</CartContext.Provider>;
}
Sau đó, tạo hook useReducer.
export const CartProvider = ({ children }) => {
const [state, dispatch] = useReducer(cartReducer, { items: [] });
return <CartContext.Provider>{children}</CartContext.Provider>;
};
Hàm điều phối chịu trách nhiệm cập nhật trạng thái giỏ hàng, vì vậy hãy sửa đổi hàm CartProvider để bao gồm các hàm gửi sản phẩm đến hook useReducer khi giỏ hàng cập nhật.
import { createContext, useReducer } from "react";export const CartProvider = ({ children }) => {
const [state, dispatch] = useReducer(cartReducer, initialState);
const addToCart = (product) => {
const updatedCart = [...state.items, product];
dispatch({
type: "ADD",
payload: {
items: updatedCart,
},
});
};
const removeFromCart = (id) => {
const updatedCart = state.items.filter(
(currentProduct) => currentProduct.id !== id
);
dispatch({
type: "REMOVE",
payload: {
items: updatedCart,
},
});
};
return <CartContext.Provider>{children}</CartContext.Provider>;
};
Hàm addToCart nối thêm sản phẩm mới vào các sản phẩm hiện có và trả về các sản phẩm đã cập nhật trong đối tượng trọng tải của hàm điều phối. Tương tự như vậy, hàm removeFromCart lọc mặt hàng theo ID và trả về danh sách đã cập nhật.
Bạn cũng cần trả về giá trị prop trong nhà cung cấp CartContext.
export const CartProvider = ({ children }) => {
const [state, dispatch] = useReducer(cartReducer, {
items: [],
}); const addToCart = (product) => {};
const removeFromCart = (id) => {};
const value = {
items: state.items,
addToCart,
removeFromCart,
};
return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
}
Giá trị prop được sử dụng thông qua hook useContext.
Sử dụng bối cảnh giỏ hàng
Cho đến giờ, bạn đã tạo ngữ cảnh giỏ hàng và tạo hàm useReducer để cập nhật giỏ hàng. Tiếp theo, bạn sẽ sử dụng ngữ cảnh giỏ hàng trong thành phần sản phẩm bằng cách sử dụng hook useContext.
Bắt đầu bằng cách gói index.js, thành phần trên cùng, với trình cung cấp ngữ cảnh để cung cấp các giá trị ngữ cảnh trên toàn bộ ứng dụng.
import { CartProvider } from "../context/cartContext";function MyApp({ Component, pageProps }) {
return (
<CartProvider>
<Component {...pageProps} />
</CartProvider>
);
}
export default MyApp;
Sau đó, nhập hook useContext và nhà cung cấp bối cảnh giỏ hàng trong Product.js
import { useContext } from "react"
import { CartContext } from "../context/cartContext"export default function Product() {
const {items, addToCart, removeFromCart} = useContext(CartContext)
return (
<>
<div>
<p>{name}</p>
<p>{price}</p>
<button>Add to Cart</button>
</div>
</>
)
}
Chức năng của nút phụ thuộc vào việc mặt hàng đó đã có trong giỏ hàng hay chưa. Nếu một mặt hàng tồn tại trong giỏ hàng, nút sẽ xóa mặt hàng đó khỏi giỏ hàng và nếu một mặt hàng chưa có trong giỏ hàng, nút sẽ thêm mặt hàng đó. Điều này có nghĩa là bạn phải theo dõi trạng thái của mục bằng cách sử dụng useEffect và useState. Mã useEffect kiểm tra xem mặt hàng đó có trong giỏ hàng hay không sau khi thành phần hiển thị trong khi useState cập nhật trạng thái của mặt hàng.
const [exists, setExists] = useState(false);useEffect(() => {
const inCart = items.find((item) => item.id === id);
if (inCart) {
setExists(true);
} else {
setExists(false);
}
}, [items, id]);
Bây giờ, sử dụng kết xuất có điều kiện để hiển thị nút dựa trên trạng thái tồn tại.
return (
<div>
<p>{name}</p>
<p>{price}</p>
{
exists
? <button onClick={() => removeFromCart(id)}>Remove from Cart</button>
: <button onClick={() => addToCart({id, name, price})}>Add to Cart</button>
}
</div>
)
Lưu ý rằng các hàm xử lý onClick là các hàm removeFromCart và addToCart được xác định trong trình cung cấp ngữ cảnh.
Thêm nhiều chức năng hơn vào giỏ hàng
Bạn đã học cách tạo giỏ hàng bằng cách sử dụng API ngữ cảnh và hook useReducer.
Mặc dù hướng dẫn này chỉ đề cập đến chức năng thêm và xóa, nhưng bạn có thể sử dụng các khái niệm tương tự để thêm nhiều tính năng hơn như điều chỉnh số lượng mặt hàng trong giỏ hàng. Điều quan trọng là hiểu API ngữ cảnh và cách sử dụng hook để cập nhật chi tiết giỏ hàng.