I have a filter component that filters a set of data. I want to output the filtered data to the DOM by using the filtered object in the local state. I cannot figure out how to use state without reseting the filter input and I can also not figure out how to output the filtered data to the DOM without using state.
This is the dataset:
const data = [
{ Name: John,
Tags: [walking, senior, Amsterdam]
},
{Name: Chris,
Tags: [biking, junior, The Hague]
},
{Name: Marc,
Tags: [walking, junior, Amsterdam]
}
I want to filter this dataset based on the tags the client selects:
<select data-categorie={hobby} onChange={filterTagHandler}>
<option value='all'>All><option>
<option value='walking'>Walking><option>
<option value='biking'>Biking><option>
<select>
<select data-categorie={age} onChange={filterTagHandler}>
<option value='all'>All><option>
<option value='junior'>Junior><option>
<option value='senior'>Senior><option>
<select>
<select data-categorie={city} onChange={filterTagHandler}>
<option value='all'>All><option>
<option value='amsterdam'>Amsterdam><option>
<option value='the hague'>The Hague><option>
<select>
The filter select components are dynamically generated from client input. Therefor there is just the filterTagHandler instead of a nameHandler, hobbyHandler, cityHandler.
First thing is to handle the selected tags and create an array from the selected tags:
const selectedTagsArray = []
const filterTagHandler = (e) => {
const option = e.target.options
const tagSelected = option[option.selectedIndex].value
const categorie = e.target.dataset.categorie
selectedTagsArray.push(tagSelected)
// Handle new option in categorie
handleNewOptionInCategorie(categorie, tagSelected)
// Handle all option
handleAllOption(tagSelected)
// Filter items
filterItems(selectedTagsArray)
}
So the first thing that happens in this onChange function is the selected tag is push to the selectedTagsArray. If I would set the selectedTagsArray to state:
const [tagsArray, setTagsArray] = useState([])
setTagsArray(selectedTagsArray)
the selectedTagsArray would be emptied every time the client selects a new filter option, because the state get’s updated. So that’s no good.
So first I use some logic to update the selectTagsArray if the client selects a new option within a categorie (select component):
const handleNewOptionInCategorie = (categorie, tagSelected) => {
filterTags && filterTags[categorie].forEach((tag) => {
if(selectedTagsArray.includes(tag.Tag) && tag.Tag !== tagSelected){
const index = selectedTagsArray.indexOf(tag.Tag)
selectedTagsArray.splice(index, 1)
}
})
}
Then I handle the ‘All’ option:
const handleAllOption = (tagSelected) => {
if(tagSelected === 'All'){
const index = selectedTagsArray.indexOf(tagSelected)
selectedTagsArray.splice(index, 1)
}
}
This all works fine (as long as there is no state change along the way).
Next I filter the data based on the selected tags:
const filterItems = (array) => {
const newArray = []
data.forEach(item => {
if(array.every(tag => item.Tags.includes(tag))){
newArray.push(item)
}
})
}
So this gives me the filtered data in the newArray object. The next logical step now would be to:
const [filteredItems, setFilteredItems] = useState(data)
setFilteredItems(newArray)
This has to be done inside the filteredItems object.
But I cannot use state here as well, since the filterItems function is called inside the filterTaghandler onChange and so every time the client selects a new option the state updates and the selectedTagsArray is emptied.
So, how can I use the newArray object to update the DOM or how can I use state without emptying the selectedTagsArray?