如何在ReactJS项目的Redux Toolkit中实现商品筛选功能
React + Redux Toolkit 商品分类与价格筛选实现方案
先明确核心原则:始终保留原始商品数据,基于原始数据做筛选,不要直接修改原始列表,这是很多筛选失效的根源。下面分步骤给出可落地的实现:
1. 调整Redux Slice的状态结构
在你的商品slice里,需要维护三个核心状态:
rawProducts:存储从接口获取的原始商品列表,永远不修改filters:存储当前筛选条件(分类、价格区间)filteredProducts:存储经过筛选后的商品列表
示例slice代码:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; // 异步获取商品 export const fetchProducts = createAsyncThunk( 'products/fetchProducts', async () => { const res = await fetch('https://dummyjson.com/products'); const data = await res.json(); return data.products; } ); const productsSlice = createSlice({ name: 'products', initialState: { rawProducts: [], filteredProducts: [], filters: { category: 'all', // 默认显示全部分类 priceMin: 0, priceMax: Infinity }, status: 'idle', error: null }, reducers: { // 更新分类筛选条件 setCategoryFilter: (state, action) => { state.filters.category = action.payload; state.filteredProducts = applyFilters(state.rawProducts, state.filters); }, // 更新价格区间筛选条件 setPriceRangeFilter: (state, action) => { state.filters.priceMin = action.payload.min; state.filters.priceMax = action.payload.max; state.filteredProducts = applyFilters(state.rawProducts, state.filters); } }, extraReducers: (builder) => { builder .addCase(fetchProducts.fulfilled, (state, action) => { state.rawProducts = action.payload; // 初始加载时应用默认筛选 state.filteredProducts = applyFilters(action.payload, state.filters); state.status = 'succeeded'; }) .addCase(fetchProducts.pending, (state) => { state.status = 'loading'; }) .addCase(fetchProducts.rejected, (state, action) => { state.status = 'failed'; state.error = action.error.message; }); } }); // 抽离筛选逻辑函数,便于维护 const applyFilters = (products, filters) => { return products.filter(product => { // 分类筛选:'all'则跳过分类判断 const matchesCategory = filters.category === 'all' || product.category === filters.category; // 价格筛选:判断商品价格在区间内 const matchesPrice = product.price >= filters.priceMin && product.price <= filters.priceMax; return matchesCategory && matchesPrice; }); }; export const { setCategoryFilter, setPriceRangeFilter } = productsSlice.actions; export default productsSlice.reducer;
2. 组件中实现筛选交互
在筛选组件(侧边栏/顶部筛选栏)中通过dispatch更新筛选条件,商品列表组件渲染filteredProducts即可:
筛选组件示例:
import { useDispatch } from 'react-redux'; import { setCategoryFilter, setPriceRangeFilter } from './productsSlice'; function ProductFilters() { const dispatch = useDispatch(); const handleCategoryChange = (e) => { dispatch(setCategoryFilter(e.target.value)); }; const handlePriceChange = () => { const minVal = parseInt(document.getElementById('price-min').value) || 0; const maxVal = parseInt(document.getElementById('price-max').value) || Infinity; dispatch(setPriceRangeFilter({ min: minVal, max: maxVal })); }; return ( <div className="filters"> <div> <label>分类:</label> <select onChange={handleCategoryChange} defaultValue="all"> <option value="all">全部</option> <option value="smartphones">智能手机</option> <option value="laptops">笔记本电脑</option> {/* 根据dummyjson返回的分类补充选项 */} </select> </div> <div> <label>价格区间:</label> <input type="number" id="price-min" placeholder="最低价格" onChange={handlePriceChange} /> <span>-</span> <input type="number" id="price-max" placeholder="最高价格" onChange={handlePriceChange} /> </div> </div> ); } export default ProductFilters;
商品列表组件示例:
import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fetchProducts } from './productsSlice'; function ProductList() { const dispatch = useDispatch(); const { filteredProducts, status, error } = useSelector(state => state.products); useEffect(() => { if (status === 'idle') { dispatch(fetchProducts()); } }, [status, dispatch]); if (status === 'loading') return <div>加载中...</div>; if (status === 'failed') return <div>加载失败:{error}</div>; return ( <div className="product-grid"> {filteredProducts.map(product => ( <div key={product.id} className="product-card"> <img src={product.thumbnail} alt={product.title} /> <h3>{product.title}</h3> <p>${product.price}</p> </div> ))} </div> ); } export default ProductList;
3. 常见失效问题排查
- 未保留原始数据:如果直接修改接口返回的商品列表做筛选,会导致后续筛选没有完整数据可用,必须单独存储
rawProducts。 - 筛选逻辑错误:检查分类匹配是否区分大小写(dummyjson的category为小写,确保选项值与接口返回一致),价格判断是否存在字符串与数字比较的情况。
- 筛选状态未更新:用Redux DevTools查看
filters状态是否在交互时正确变化,若未变化,检查dispatch调用是否正确、action类型是否匹配。
内容的提问来源于stack exchange,提问作者Pavitar Sharma
相关产品推荐
相关产品推荐

