I am unable to filter and sort at the same time. I will be getting products
from axios get call and create a copy of it into filteredProducts
initially. Then i will be clicking on sort
and discount
filter options. Sorting is working fine here but not together with discount
filter. How can i achieve this together inside useEffect
?
const [filteredProducts, setFilteredProducts] = useState([]);
const handleSort = (sortByValue) => {
return filteredProducts.sort((a, b) => {
switch(sortByValue) {
case 'new' : return parseISO(b.created_at) - parseISO(a.created_at);
case 'discount' : return b.discount - a.discount;
case 'price_desc' : return b.price - a.price;
case 'price_asc' : return a.price - b.price;
default : return a.name.localeCompare(b.name);
}
})
}
const discount = queryParams.get('discount')
const sortBy = queryParams.get('sort')
const handleDiscountFilters = (filterResults) => {
if(discount) {
return filteredProducts.filter((product) => product.discount > discount)
} else {
return products
}
}
// Here i want to call the different filter functions first and then call sort function.
useEffect(() => {
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults)
filterResults = handleSort(sortBy)
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy])
3
Answers
You have to pass the array to the
handleSort
function. Otherwise you sort the initial array, not the filtered oneThere are a few problems with your code. The first is that you are modifying and setting
filterResults
in the sameuseEffect
hook, which means you will have an infinite loop. Every time you callsetFiltereddProducts
the reference value offilteredProducts
changes, which will cause youruseEffect
to fire again.Next, similar to how you pass the
filterResults
intohandleDiscountFilters
, you also need to do that forhandleSort
. Right nowhandleSort
is reading from the top-levelfilteredProducts
, which isn’t being impacted by your filters:But, except for the network call, you really don’t need a
useEffect
at all for this:The problem is that
handleSort
uses the value declared in the first line of the code, so the value offilterResults
assigned from the return value ofhandleDiscountFilters
is lost, you are always using the unfiltered data.So, to correct that I would add a parameter to the
handleSort
function, and use that parameter, instead of the const declared in the first line:That’s about why the filtering is being ignored, but there are other problems, I think: isn’t this being rendered continously in a loop? Because the
handle___
functions are new ones every render, so the useEffect will be invoked also in every render and useEffect is always invokingsetFilteredProducts
, so it will trigger another render, so it never stops rendering. Also, if you set the value after the first render the filtered data would remain filtered (the values filtered out will be lost). I would have a state-associated variable for the source unfiltered data and another derived from it for the filtered data.