如何在ReactJS项目的redux-toolkit中实现购物车项目中的按类别过滤。我在filterSlice.js文件中尝试过,但我没有得到数据不是按类别过滤的意思。请帮助我,我应该在我的代码中实现什么产品类别过滤器在我的项目中。我只想通过使用redux-toolkit在类别中过滤器,如(笔记本电脑,智能手机,家居装饰等)。
Home.js
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Products, SearchBar } from "../components";
import Filters from "../components/Filters";
import { fetchProducts, handleSearchProducts, STATUSES } from "../redux/features/productSlice";
import { FaFilter } from "react-icons/fa";
import SidebarFilterPanel from "../components/SidebarFilterPanel";
import { setCategoryFilter } from "../redux/features/filterSlice";
const categories = [
"Smartphones",
"Laptops",
"Fragrances",
"Skincare",
"Groceries",
"Home-Decoration",
];
const Home = () => {
const dispatch = useDispatch();
const { products, status } = useSelector((state) => state.product.products);
const { price, rating, discount, category } = useSelector(state => state.filters)
console.log(products);
const [searchTerm, setSearchTerm] = useState("")
const [openFilter, setOpenFilter] = useState(false);
const openFilterPanel = () => setOpenFilter(!openFilter);
useEffect(() => {
dispatch(fetchProducts())
}, [dispatch]);
useEffect(() => {
document.title = "Shoping Website";
}, []);
const searchProducts = products?.filter(product => {
if(!searchTerm.length) return product
if(!product.title) return
return product.title.toLowerCase().includes(searchTerm.toLowerCase())
})
const handleSearch = (event) => {
setSearchTerm(event.target.value)
}
const handleFilterCategory = (category) => {
const filterCategory = products?.filter(product => product.category === category)
dispatch(setCategoryFilter(filterCategory))
}
return (
<div>
<div className="flex gap-4 justify-between px-4">
<div className="hidden md:block">
<Filters categories={categories} handleFilterCategory={handleFilterCategory} />
</div>
<div className="flex flex-col items-center justify-center w-full">
<div className="flex items-center">
<SearchBar handleSearch={handleSearch} />
<div
onClick={openFilterPanel}
className={`bg-black text-white py-[10px] px-3 md:hidden block rounded cursor-pointer ml-2 mt-3 duration-1000 transition-all`}
>
<FaFilter onClick={openFilterPanel} />
</div>
{openFilter && <SidebarFilterPanel categories={categories} />}
</div>
<div className="flex flex-wrap gap-4 p-2 items-center justify-center mr-auto ml-auto w-full mt-4">
{searchProducts &&
searchProducts
?.filter((product) => product.price <= price)
?.filter((product => product.rating <= rating))
?.filter((product) => product.discountPercentage <= discount)
?.map((product) => (
<Products key={product.id} product={product} />
))}
</div>
</div>
</div>
</div>
);
};
export default Home;
filterSlice.js
import { createSlice } from "@reduxjs/toolkit";
const filterSlice = createSlice({
name: "filters",
initialState: {
price: 1500,
rating: 5,
discount: 20,
category: []
},
reducers: {
setPriceFilter: (state, action) => {
state.price = Math.max(0, action.payload);
},
setRatingFilter: (state, action) => {
state.rating = Math.max(0, action.payload)
},
setDiscountFilter: (state, action) => {
state.discount = Math.max(0, action.payload)
},
setCategoryFilter: (state, action) => {
state.category.push(action.payload)
}
},
});
export const actions = {
...filterSlice.actions,
};
export const { setPriceFilter, setRatingFilter, setDiscountFilter, setCategoryFilter } = filterSlice.actions
export default filterSlice.reducer;
productSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
const baseURL = "https://dummyjson.com/products";
export const STATUSES = Object.freeze({
IDLE: "idle",
ERROR: "error",
LOADING: "loading",
});
export const fetchProducts = createAsyncThunk(
"products/fetch",
async () => {
const res = await axios.get(baseURL);
const data = await res.data;
return data;
}
);
export const getProduct = createAsyncThunk(
"product/getProduct",
async (id, { rejectWithValue }) => {
try {
const response = await axios.get(`${baseURL}/${id}`);
console.log(id);
return response.data;
} catch (error) {
return rejectWithValue(error.response);
}
}
);
const productSlice = createSlice({
name: "product",
initialState: {
products: [],
product: {},
status: STATUSES.IDLE,
},
reducers: {
},
extraReducers: (builder) => {
builder
.addCase(fetchProducts.pending, (state, action) => {
state.status = STATUSES.LOADING;
})
.addCase(fetchProducts.fulfilled, (state, action) => {
state.products = action.payload;
state.status = STATUSES.IDLE;
})
.addCase(fetchProducts.rejected, (state, action) => {
state.status = STATUSES.ERROR;
})
.addCase(getProduct.pending, (state, action) => {
state.status = STATUSES.LOADING;
})
.addCase(getProduct.fulfilled, (state, action) => {
state.status = STATUSES.IDLE;
state.product = action.payload;
});
},
});
export const { handlePriceFilter, handleSearchProducts } = productSlice.actions;
export default productSlice.reducer;
import React from "react";
import Slider from "@mui/material/Slider";
import { useDispatch, useSelector } from "react-redux";
import { setPriceFilter, setRatingFilter, setDiscountFilter, setCategoryFilter } from "../redux/features/filterSlice";
过滤器
const Filters = ({ categories, handleFilterCategory }) => {
const dispatch = useDispatch();
const price = useSelector((state) => state.filters.price);
const rating = useSelector((state) => state.filters.rating);
const discount = useSelector((state) => state.filters.discount);
const category = useSelector((state) => state.filters.category);
console.log(price);
return (
<div className=" w-[200px] shadow-lg h-[500px] flex flex-col px-2 py-10">
<div className="w-[150px] ml-auto mr-auto flex flex-col gap-2">
<p className="font-bold">Price</p>
<Slider
valueLabelDisplay="auto"
aria-labelledby="range-slider"
min={0}
max={1500}
value={price}
onChange={(event, value) => dispatch(setPriceFilter(value))}
/>
</div>
<div className="px-2 mt-6">
<p className="font-bold mb-2">Catogries</p>
{categories.map((category, index) => (
<p
className="cursor-pointer text-sm my-2 hover:text-orange-500"
key={index}
onClick={() => handleFilterCategory(category)}
>
{category}
</p>
))}
</div>
<div className="w-[150px] pl-2 flex flex-col gap-2 my-2">
<p className="font-bold">Discount</p>
<Slider
valueLabelDisplay="auto"
aria-labelledby="range-slider"
min={0}
max={20}
value={discount}
onChange={(event, value) => dispatch(setDiscountFilter(value))}
/>
</div>
<div className="w-[150px] pl-2 flex flex-col gap-2">
<p className="font-bold">Rating</p>
<Slider
valueLabelDisplay="auto"
aria-labelledby="range-slider"
min={0}
max={5}
value={rating}
onChange={(event, value) => dispatch(setRatingFilter(value))}
/>
</div>
</div>
);
};
export default Filters;
1条答案
按热度按时间3lxsmp7m1#
您希望以处理价格和等级过滤器的相同方式处理类别过滤器,即:
Filters
组件从reduxfilters
状态访问当前过滤器。Filters
组件通过调度有效负载为过滤器新值的操作来处理对当前过滤器的更改。filterSlice
响应该操作并更新reduxfilters
状态。Products
组件从reduxfilters
状态访问当前筛选器值,并从product
状态访问未筛选的产品列表。Products
组件在显示产品数组之前将筛选器应用于产品数组。(步骤4和5也可以通过使用
createSelector
选择过滤产品列表来实现)相反,您现在所做的是将一个过滤后的产品数组调度到redux状态,而不是调度过滤器的值。