Reputation: 684
How to not lose React state in this case when I do filter?
When I do filter I lose my previous state and program work not correct, for example, if I choose category sport, then try category fashion, I can't see anything in fashion, the case this all was dropped, when I choose sport.
I am new in React I would like to hear the best practices.
FilterCategory(e) {
// Filter
const filter = this.state.items.filter(
(item) => {
return item.category.indexOf(e.target.name) !== -1
}
)
// Update state
this.setState({
items:filter
})
}
Upvotes: 0
Views: 3694
Reputation: 9787
You can just store and update the filter
query in state and only return the filtered items in the render
function instead of updating state.
class App extends React.Component {
state = {
items: [
{ category: ['fashion'], name: 'Gigi Hadid', id: 1 },
{ category: ['sports'], name: 'Lebron James', id: 2 },
{ category: ['fashion', 'sports'], name: 'Michael Jordan', id: 3 },
{ category: ['sports', 'tech'], name: 'Andre Iguodala', id: 4 },
{ category: ['tech'], name: 'Mark Zuckerberg', id: 5 },
],
filter: '',
}
handleChange = (e) => {
this.setState({ filter: e.target.value });
}
render() {
const { items, filter } = this.state;
let shownItems = items;
if (filter) {
shownItems = items.filter(({ category }) => category.includes(filter));
}
return (
<div>
<select value={filter} onChange={this.handleChange}>
<option value="">All</option>
<option value="fashion">Fashion</option>
<option value="sports">Sports</option>
<option value="tech">Tech</option>
</select>
<div>
<ul>
{shownItems.map(({ name, id }) => <li key={id}>{ name }</li>)}
</ul>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Upvotes: 0
Reputation: 1938
Why not use query string to store filters.
Suppose your url is /products and filter selected is say gender male. then you can append /products?gender=male.
Now in react using libraries like react-router you can access this query params and get the current filter selected and then perform whatever options you want to like call api etc.
If you further select other filters then just append the new filters again to query params like field1=value1&field2=value2&field3=value3...
And again as location props of react will change you will get the new params in the component.
Advantages of this technique. 1) No headache of maintaining state. Storing filters in state can become complex and clumsy if not done in proper way.
2) No problem if page gets refreshed. Suppose your user have selected filters and, page gets refreshed, all filters will be lost if saved in state. But if query string is done it will remain intact.
Due to this reasons i think query string is better option then state.
Upvotes: 2
Reputation: 1073
The problem is you're setting items to the filtered array returned by filter.
You could use another proprety in your state to store the target's item, so you're keeping your items as they are, something like this:
this.state({
items: [...yourItems],
chosenItem: []
})
filterCategory(e) {
let filter = this.state.items.filter((item) => {
item.category.indexOf(e.target.name) !== -1
})
// Update state keeping items intact
this.setState({
chosenItem: filter
})
}
Upvotes: 1
Reputation: 4289
Just store filtered values as another state property.
state = {
items: [],
filteredItems: []
}
When you do filtering always refer to items
and override filteredItems
filterItems(e) {
const filtered = this.state.items.filter(
(item) => {
return item.category.indexOf(e.target.name) !== -1
}
)
this.setState({filteredItems: filtered});
}
Upvotes: 1