使用Redux Toolkit无法查看购物车商品的技术问题排查
问题描述
我正在开发一个React小项目,计划用Redux Toolkit实现购物车逻辑。需求是:点击“Add To Bag”按钮时,将商品的数量、颜色、名称、品牌等信息添加为购物车中的一件商品,打开购物车页面时能渲染这些商品。
相关代码
Index.js
import { Provider } from "react-redux"; import { store } from "./Redux/Store"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <> <Provider store={store}> <App /> </Provider> </> );
Store.js
import { configureStore } from "@reduxjs/toolkit"; import cartReducer from "./Slices/CartSlices"; export const store = configureStore({ reducer: { cart1: cartReducer, }, });
CartSlices.js
import { createSlice } from "@reduxjs/toolkit"; const cartSlice = createSlice({ name: "Cart", initialState: [], reducers: { addItem: (state, action) => { state.push(action.payload); }, }, }); export const { addItem } = cartSlice.actions; export default cartSlice.reducer;
SingleProduct.js
import React, { useEffect, useState } from "react"; import { Link, useLocation } from "react-router-dom"; import "./SingleProduct.css"; import { addItem } from "../Redux/Slices/CartSlices"; import { useDispatch } from "react-redux"; function SingleProduct() { const location = useLocation(); const productData = location.state?.data; const dispatch = useDispatch(); const [selectedColorIndex, setSelectedColorIndex] = useState(null); const [selectedQuantity, setSelectedQuantity] = useState(0); const QuantitySelect = () => { const options = Array.from({ length: 10 }).map((_, i) => ( <option key={i} value={i}> {i} </option> )); return options; }; return ( <section> <div className="row"> <div className="col-md-6"> <img src={productData.attributes.image} alt="" className="mt-5 rounded-5 ms-5 shadow" style={{ objectFit: "cover", height: "400px", width: "550px", }} /> </div> <div className="col-md-6 mt-5"> <h2 className="fw-bold">{productData.attributes.title}</h2> <h5 className="fw-bold text-black-50 mt-3"> {productData.attributes.company} </h5> <p className="mt-3"> <span>$</span> {productData.attributes.price} </p> <p className="lead fs-6 fw-light lh-lg"> {productData.attributes.description} </p> <div> <p className="fw-bold"> Colors</p> <div className="d-flex"> {productData.attributes.colors.map((color, index) => ( <div key={index} className={`dot ${selectedColorIndex === index ? "selected-dot" : ""}`} style={{ backgroundColor: color }} onClick={() => setSelectedColorIndex(index)} ></div> ))} </div> <div> <p className="mt-3 fw-bold">Quantity</p> <select className="form-select w-50 rounded-3" value={selectedQuantity} onChange={(e) => setSelectedQuantity(e.target.value)} > <QuantitySelect /> </select> </div> {/* <Link to="/cart"> */} <div className="btn mt-4 text-white" style={{ backgroundColor: "#463aa1", height: "40px" }} onClick={(e) => dispatch( addItem({ image: productData.attributes.image, companyName: productData.attributes.company, price: productData.attributes.price, title: productData.attributes.title, color: selectedColorIndex, quantity: selectedQuantity, }) ) } > Add To Bag </div> {/* </Link> */} </div> </div> </div> {/* Empty div for space */} <div style={{ height: "50px" }}></div> </section> ); } export default SingleProduct;
Cart.js
import { useSelector } from "react-redux"; function Cart() { const items = useSelector((state) => state); console.log("Items : ", items); // render code }
App.js
import "./App.css"; import { RouterProvider, createBrowserRouter } from "react-router-dom"; import { About, Cart, Checkout, Error, HomeLayout, Landing, Login, Orders, Products, Register, SingleProduct, } from "./pages"; const router = createBrowserRouter([ { path: "/", element: <HomeLayout />, errorElement: <Error />, children: [ { index: true, element: <Landing />, }, { path: "products", element: <Products />, }, { path: "products/:id", element: <SingleProduct />, }, { path: "cart", element: <Cart />, }, { path: "about", element: <About />, }, { path: "checkout", element: <Checkout />, }, { path: "orders", element: <Orders />, }, ], }, { path: "/login", element: <Login />, errorElement: <Error />, }, { path: "/register", element: <Register />, errorElement: <Error />, }, ]); function App() { return <RouterProvider router={router} />; } export default App;
Navbar.jsx
import React, { useEffect, useState } from "react"; import { BsSunFill, BsMoonFill, BsCart3 } from "react-icons/bs"; import { FaBarsStaggered } from "react-icons/fa6"; import { NavLink } from "react-router-dom"; import { NavLinks } from "./NavLinks"; import { useSelector } from "react-redux"; function Navbar() { const items = useSelector((state) => state); return ( <nav className="navbar navbar-expand-sm navbar-clr"> <div className="container"> <NavLink to="/" className=" navbar-brand btn btn-sm fs-6 d-none d-md-block text-white fs-6" style={{ background: "#016efe" }} > C </NavLink> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"> <FaBarsStaggered className="text-white" /> </span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav mx-auto "> <li class="nav-item"> <a class="nav-link active text-black mx-3" aria-current="page" href="/" > Home </a> </li> <li class="nav-item"> <a class="nav-link text-black mx-3" href="about"> About </a> </li> <li class="nav-item"> <a class="nav-link text-black mx-3" href="product"> Product </a> </li> <li class="nav-item"> <a class="nav-link text-black mx-3 " // style={{ background: "#02152c" }} href="/cart" > Cart </a> </li> <li class="nav-item"> <a class="nav-link text-black mx-3" href="checkout"> Checkout </a> </li> <li class="nav-item"> <a class="nav-link text-black mx-3" href="orders"> Orders </a> </li> </ul> {/* <NavLinks /> */} </div> <NavLink to="/cart" class="position-relative"> <div> <BsCart3 style={{ height: "30px", width: "30px" }} className="text-black" /> <span class="position-absolute top-5 start-90 translate-middle badge rounded-pill" style={{ background: "#016efe" }} > {items.cart1.length} </span> </div> </NavLink> </div> </nav> ); } export default Navbar;
问题现象
通过Redux DevTools调试时,发现购物车中有2件商品(符合预期),但在Cart.js中打印控制台时却看不到这些商品。
观察发现:如果点击“Add To Bag”后立即通过Link标签跳转到购物车页面,能看到商品;但单独进入购物车页面时,就会出现上述问题。
问题原因及解决方法
核心问题:路由跳转方式错误
Navbar中使用了原生<a>标签跳转路由,比如:
<a class="nav-link text-black mx-3 " href="/cart">Cart</a>
原生<a>标签会触发页面完全刷新,导致Redux store中的数据全部丢失,所以单独从Navbar进入购物车页面时看不到之前添加的商品。而点击“Add To Bag”后用Link跳转是单页应用的无刷新跳转,store数据得以保留,所以能看到商品。
解决步骤
替换所有原生
<a>标签为React Router的<NavLink>或<Link>
修改Navbar中的导航链接,示例如下:<li class="nav-item"> <NavLink class="nav-link active text-black mx-3" to="/"> Home </NavLink> </li> <li class="nav-item"> <NavLink class="nav-link text-black mx-3" to="/about"> About </NavLink> </li> <li class="nav-item"> <NavLink class="nav-link text-black mx-3" to="/products"> Product </NavLink> </li> <li class="nav-item"> <NavLink class="nav-link text-black mx-3" to="/cart"> Cart </NavLink> </li> <li class="nav-item"> <NavLink class="nav-link text-black mx-3" to="/checkout"> Checkout </NavLink> </li> <li class="nav-item"> <NavLink class="nav-link text-black mx-3" to="/orders"> Orders </NavLink> </li>确保已经导入
NavLink:import { NavLink } from "react-router-dom";优化Cart组件的state选择器
当前Cart.js中直接取整个state,应精准获取cart1切片的数据:const items = useSelector((state) => state.cart1);这样控制台打印的就是购物车的商品数组,方便后续渲染。
可选:添加持久化存储(防止页面刷新丢失数据)
如果希望页面刷新后购物车数据依然保留,可以使用redux-persist库:- 安装依赖:
npm install redux-persist - 修改Store.js:
import { configureStore } from "@reduxjs/toolkit"; import { persistStore, persistReducer } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; // 默认localStorage import cartReducer from "./Slices/CartSlices"; const persistConfig = { key: 'root', storage, }; const persistedReducer = persistReducer(persistConfig, cartReducer); export const store = configureStore({ reducer: { cart1: persistedReducer, }, }); export const persistor = persistStore(store); - 修改Index.js,添加PersistGate:
import { Provider } from "react-redux"; import { store, persistor } from "./Redux/Store"; import { PersistGate } from 'redux-persist/integration/react'; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <> <Provider store={store}> <PersistGate loading={null} persistor={persistor}> <App /> </PersistGate> </Provider> </> );
- 安装依赖:
内容的提问来源于stack exchange,提问作者tushar
相关产品推荐
相关产品推荐

