刷新Category.js页面后用户所选类别不持久化,如何解决?
问题
在DropdownTab.js选完商品类别跳转到Category.js后,刷新页面会丢失所选类别的状态。试把productsReducer加到store.js的rootReducer里做持久化,结果出现fetchAllProductsStatus未定义的错误;但如果把productsReducer放在configureStore的reducer字段里而不是rootReducer,类别选择功能正常,却没法持久化状态。
解决方法
问题根源在Redux Persist的配置和store结构上:
- 把productsReducer放在rootReducer外面时,它不在持久化范围内,刷新自然丢状态;
- 放到rootReducer里后,原来的selector路径错了——因为此时products状态嵌套在persistedReducer下面,不是根级,所以找不到
fetchAllProductsStatus。
正确做法是把所有要持久化的reducer都放进rootReducer,统一做持久化,同时保证selector路径和store结构匹配。
修改后的store.js
import { combineReducers, configureStore } from "@reduxjs/toolkit" import { persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER, } from 'redux-persist' import storage from 'redux-persist/lib/storage' import adminAdvertisementReducer from "./features/admin/advertisementSlice" import usersReducer from "./features/users/usersSlice" import cartReducer from "./features/cart/cartSlice" import ordersReducer from "./features/orders/ordersSlice" import productsReducer from "./features/products/productsSlice" const persistConfig = { key: "root", version: 1, storage, // 可选:如果某些reducer不需要持久化,可以在这里排除 // blacklist: ['adminMainAdvertisement', 'orders'] } // 将所有需要持久化的reducer合并到rootReducer const rootReducer = combineReducers({ cart: cartReducer, users: usersReducer, products: productsReducer, adminMainAdvertisement: adminAdvertisementReducer, orders: ordersReducer }) const persistedReducer = persistReducer(persistConfig, rootReducer) export const store = configureStore({ // 直接使用persistedReducer作为根reducer,保持状态结构扁平化 reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }), })
优化后的Category.js(兼容刷新场景)
直接从URL参数获取类别,不用完全依赖redux状态,同时同步更新redux里的categoryTheme:
import "./category.css"; import { useDispatch, useSelector } from "react-redux"; import { fetchProductsByCategory, setCategoryTheme, selectFetchProductsByCategoryStatus, selectProductsInCategory } from "../../features/products/productsSlice"; import { Link, useParams } from "react-router-dom"; import { useEffect, useState } from "react"; const ProductCategory = () => { const dispatch = useDispatch() const { category } = useParams() // 直接从URL取当前类别 const fetchProductsByCategoryStatus = useSelector(selectFetchProductsByCategoryStatus) const productsInCategory = useSelector(selectProductsInCategory) const [currentCategory, setCurrentCategory] = useState("") useEffect(() => { if (category) { dispatch(fetchProductsByCategory(category)) dispatch(setCategoryTheme(category)) // 同步更新redux里的主题 } }, [dispatch, category]) useEffect(() => { if (fetchProductsByCategoryStatus === "succeeded" && productsInCategory.length > 0) { setCurrentCategory(productsInCategory[0].category) } }, [fetchProductsByCategoryStatus, productsInCategory]) return ( <div className="container p2" style={{minHeight:"100vh"}}> <nav aria-label="breadcrumb"> <ol class="breadcrumb" style={{fontFamily:"serif", fontSize:"0.6rem", marginTop:"0.4rem", marginBottom:"0.4rem"}}> <li class="breadcrumb-item"><Link to ="/">Home</Link></li> <li class="breadcrumb-item active" aria-current="page">{currentCategory || category}</li> </ol> </nav> <div style={{fontFamily:"serif"}}>{currentCategory || category}</div> <div className="d-md-flex justify-content-center align-items-center"> { productsInCategory.length <= 0 ? <p>This category is currently empty.</p> : productsInCategory.map(item => { return ( <div key={item.id} className="card shadow m-md-2 my-2 col-12 col-md-4"> <img src={item.img_url} class="card-img-top" alt="item in category" /> <div class="card-body setCardBody"> <p class="card-title"><b>Name: </b><span>{item.title}</span></p> <div> <span><b>Price: $ </b>{item.price}</span> <span> | <b>Status: </b>{item.status}</span> </div> <p class="card-text"><b>Description: </b><span>{item.description}</span></p> <button class="btn btn-primary setCardBody">Add to cart</button> </div> </div> )}) } </div> </div> ); } export default ProductCategory;
说明
- store.js修改:把所有reducer合并到rootReducer后生成持久化reducer,这样所有状态(包括products)都会被持久化,同时保持state结构扁平化,原来的selector可以正常使用
state.products.xxx。 - Category.js优化:从URL直接取类别,刷新页面也能拿到当前分类并重新请求数据,同时同步更新redux状态,保证功能一致性。
内容的提问来源于stack exchange,提问作者Biruskai
相关产品推荐
相关产品推荐

