You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 13:01:05