Есть компонент в React с несколькими фильтрами контента.
--- Первый - текстовый поиск:
<div className="search-bar filter">
<input type="text"
name="search"
id='search'
onChange={handleChange}
value={search}
placeholder = "Enter a title"
className="filter-item"/>
</div>
Второй - поиск по цвету. Есть сет с цветами, который берет их из базы данных предметов, и мапит эти цвета в теги :
<select name="color"
id="color"
onChange={handleChange}
value={color}
className="filter-item select">
{
colors.map((color, index) => {
return (
<option key={index} value={color}> {color} </option>
)
})
}
</select>
Третий - поиск по цене. Задано минимальное значение товаров, и максимальное. Ползунком выбирается нужная сумма, и компонент рендерит количество товаров, которое соответствует <= заданной цены.
<input
type="range"
name="price"
id="price"
min={min}
max={max}
value={price}
className="range-price"
onChange = {handleChange}
/>
В эти фильтры передаются необходимые данные из state.
state = {
search: '',
price: 0,
min: 0,
max: 0,
color: 'all',
cup: 'all',
}
Работает по такому принципу. Как только в фильтре происходит изменение, срабатывает функция handleChange, и потом активирует другую функцию, которая уже фильтрует все запросы, изменяет значение state массива элементов, и рендерит то количество элементов, которое соответствует параметрам в фильтрах.
handleChange = (event) => {
const name = event.target.name;
const value = event.target.type === "checkbox"
? event.target.checked
: event.target.value;
this.setState({
[name]: value
},
this.sortData
);
};
sortData = () => {
const {storeProducts, price, color, cup, shipping, search} = this.state;
let tempProducts = [...storeProducts];
let tempPrice = parseInt(price);
// ---------- Filter by price
tempProducts = tempProducts.filter(item => item.price <= tempPrice);
// ---------- Filter by colors
if (color !== "all") {
tempProducts = tempProducts.filter(item => item.color === color)
}
// ---------- Filter by checkbox
if(shipping) {
tempProducts = tempProducts.filter(item => item.freeShipping === true)
}
if(search.length > 0) {
tempProducts = tempProducts.filter(item => {
let tempSearch = search.toLowerCase();
let tempTitle = item.title.toLowerCase().slice(0, search.length);
if (tempSearch === tempTitle) {
return item;
}
});
}
this.setState ({
filteredProducts: tempProducts
})
}
Все эти фильтры между собой можно совмещать. Сначала выбрать цвет, потом среди элементов выбранного цвета можно установить цену - все будет отображаться корректно. Но потом я добавил еще один фильтр, по размеру, но почему-то совместно с другими он работает неправильно, потому как работает в паре только с текстовым фильтром. Если задать фильтр по размеру, а потом или цену, или цвет - ничего. Если сначала выбрать, например цвет, а потом размер - настройки цвета сбиваются, и выдается лишь размер, то есть он перебивает все прошлые фильтры.
Фильтр этот выглядит так:
<select name="cup"
id="cup"
onChange={handleChange}
className="filter-item select">
<option value="all" >all</option>
<option value="A" >A</option>
<option value="B" >B</option>
<option value="C" >C</option>
<option value="D" >D</option>
</select>
И после дописал условие для него в функцию sortData:
if (cup === "A") {
tempProducts = brasAll.filter(item => item.cup.includes("A"))
} else if (cup === "B") {
tempProducts = brasAll.filter(item => item.cup.includes("B"))
} else if (cup === "C") {
tempProducts = brasAll.filter(item => item.cup.includes("C"))
} else if (cup === "D") {
tempProducts = brasAll.filter(item => item.cup.includes("D"))
}
Финальная функция выглядит так:
sortData = () => {
const {storeProducts, price, color, cup, shipping, search} = this.state;
let tempProducts = [...storeProducts];
let tempPrice = parseInt(price);
let brasAll = storeProducts.filter(item => item.type === "Bras");
// ---------- Filter by price
tempProducts = tempProducts.filter(item => item.price <= tempPrice);
// ---------- Filter by colors
if (color !== "all") {
tempProducts = tempProducts.filter(item => item.color === color)
}
// ---------- Filter by Cup
if (cup === "A") {
tempProducts = brasAll.filter(item => item.cup.includes("A"))
} else if (cup === "B") {
tempProducts = brasAll.filter(item => item.cup.includes("B"))
} else if (cup === "C") {
tempProducts = brasAll.filter(item => item.cup.includes("C"))
} else if (cup === "D") {
tempProducts = brasAll.filter(item => item.cup.includes("D"))
}
// ---------- Filter by checkbox
if(shipping) {
tempProducts = tempProducts.filter(item => item.freeShipping === true)
}
if(search.length > 0) {
tempProducts = tempProducts.filter(item => {
let tempSearch = search.toLowerCase();
let tempTitle = item.title.toLowerCase().slice(0, search.length);
if (tempSearch === tempTitle) {
return item;
}
});
}
this.setState ({
filteredProducts: tempProducts
})
}
Может будуть у кого-то идеи, почему новый фильтр работает не в связке с остальными и перебивает их значения?