Я не могу фильтровать и сортировать одновременно. Я буду получать products от axios get call и сначала создавать его копию в filteredProducts. Затем я буду нажимать на параметры фильтра sort и discount. Здесь сортировка работает нормально, но не вместе с фильтром discount. Как я могу достичь этого вместе внутри 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])



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы должны передать массив функции 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(filterProducts, sortBy);
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy]);
Есть несколько проблем с вашим кодом. Во-первых, вы изменяете и устанавливаете filterResults в одном и том же хуке useEffect, что означает, что у вас будет бесконечный цикл. Каждый раз, когда вы вызываете setFiltereddProducts, эталонное значение filteredProducts изменяется, что заставит ваш useEffect снова срабатывать.
Далее, аналогично тому, как вы передаете filterResults в handleDiscountFilters, вам также нужно сделать это для handleSort. Прямо сейчас handleSort читает с верхнего уровня filteredProducts, на который не влияют ваши фильтры:
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults)
filterResults = handleSort(filterResults, sortBy)
Но, кроме сетевого звонка, для этого вообще не нужен useEffect:
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>
);
Этот краткий код был именно тем, что я искал. Это сработало!
Проблема в том, что handleSort использует значение, объявленное в первой строке кода, поэтому значение filterResults, присвоенное из возвращаемого значения handleDiscountFilters, теряется, вы всегда используете нефильтрованные данные.
Итак, чтобы исправить это, я бы добавил параметр в функцию handleSort и использовал этот параметр вместо константы, объявленной в первой строке:
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])
Вот почему фильтрация игнорируется, но есть и другие проблемы, я думаю: разве это не отображается непрерывно в цикле? Поскольку функции handle___ являются новыми при каждом рендеринге, поэтому useEffect будет вызываться также при каждом рендеринге, а useEffect всегда вызывает setFilteredProducts, поэтому он запускает другой рендеринг, поэтому он никогда не останавливает рендеринг. Кроме того, если вы установите значение после первого рендеринга, отфильтрованные данные останутся отфильтрованными (отфильтрованные значения будут потеряны). У меня была бы переменная, связанная с состоянием, для исходных нефильтрованных данных и другая, полученная из нее, для отфильтрованных данных.
sortиfilter— это две разные вещи, которые не следует путать. Сначалаfilterданные, а потомsortони. Но если выsortсделаете это сначала, а потомfilterвам придетсяsortснова, так как не гарантируется, что отфильтрованные данные будут отсортированы.