英文:
Filter and sort together in react
问题
以下是您要翻译的代码部分:
我无法同时筛选和排序。我将从axios获取`products`,并将其初始复制到`filteredProducts`中。然后,我将点击`sort`和`discount`筛选选项。排序在这里正常工作,但与`discount`筛选一起不起作用。如何在`useEffect`中实现这一点?
```javascript
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
}
}
// 这里我想首先调用不同的筛选函数,然后调用排序函数。
useEffect(() => {
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults)
filterResults = handleSort(sortBy)
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy])
英文:
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])
答案1
得分: 1
你需要将数组传递给handleSort
函数,否则你将对初始数组进行排序,而不是过滤后的数组。
const handleSort = (products, sortByValue) => {
return products.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);
}
});
};
useEffect(() => {
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults);
filterResults = handleSort(filterResults, sortBy);
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy]);
英文:
You have to pass the array to the handleSort
function. Otherwise you sort the initial array, not the filtered one
const handleSort = (products, sortByValue) => {
return products.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);
}
});
};
useEffect(() => {
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults);
filterResults = handleSort(filterProducts, sortBy);
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy]);
答案2
得分: 1
以下是翻译好的内容:
-
There 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:
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults)
filterResults = handleSort(filterResults, sortBy)
- But, except for the network call, you really don't need a
useEffect
at all for this:
const [products, setProducts] = useState([]);
useEffect(async () => {
const response = await axios.get("someUrl");
setProducts(response.data);
}, []);
const discount = queryParams.get('discount');
const sortBy = queryParams.get('sort');
const shouldFilterProduct = (product) => {
if (discount) {
return product.discount > discount;
} else {
return false;
}
};
const sortProduct = (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 filteredAndSortedProducts = products
.filter(filterProduct)
.sort(sortProduct);
return (
<div>
{filteredAndSortedProducts.map(product => {
return <div>{product.name}</div>;
})}
</div>
);
英文:
There are a few problems with your code. The first is that you are modifying and setting filterResults
in the same useEffect
hook, which means you will have an infinite loop. Every time you call setFiltereddProducts
the reference value of filteredProducts
changes, which will cause your useEffect
to fire again.
Next, similar to how you pass the filterResults
into handleDiscountFilters
, you also need to do that for handleSort
. Right now handleSort
is reading from the top-level filteredProducts
, which isn't being impacted by your filters:
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults)
filterResults = handleSort(filterResults, sortBy)
But, except for the network call, you really don't need a useEffect
at all for this:
const [products, setProducts] = useState([]);
useEffect(async () => {
const response = await axios.get("someUrl");
setProducts(response.data);
}, []);
const discount = queryParams.get('discount');
const sortBy = queryParams.get('sort');
const shouldFilterProduct = (product) => {
if (discount) {
return product.discount > discount;
} else {
return false;
}
};
const sortProduct = (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 filteredAndSortedProducts = products
.filter(filterProduct)
.sort(sortProduct);
return (
<div>
{filteredAndSortedProducts.map(product => {
return <div>{product.name}</div>;
})}
</div>
);
答案3
得分: 1
The problem is that handleSort
uses the value declared in the first line of the code, so the value of filterResults
assigned from the return value of handleDiscountFilters
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:
const [filteredProducts, setFilteredProducts] = useState([]);
const handleSort = (values, sortByValue) => {
return values.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(filterResults, sortBy)
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy])
That's about why the filtering is being ignored, but there are other problems, I think: isn't this being rendered continuously 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 invoking setFilteredProducts
, 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.
英文:
The problem is that handleSort
uses the value declared in the first line of the code, so the value of filterResults
assigned from the return value of handleDiscountFilters
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:
const [filteredProducts, setFilteredProducts] = useState([]);
const handleSort = (values, sortByValue) => {
return values.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(filterResults, sortBy)
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy])
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 invoking setFilteredProducts
, 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论