Reputation: 3
I am creating a simple list of cards and I need to filter it according to which tags are selected. I have:
function Homepage() {
const [cards, setCards] = useState([]);
const [filteredCards, setFilteredCards] = useState([]);
let filteredTags = [];
The tags are buttons with onClick={toggleSingleTag}
and then I have this function:
function toggleSingleTag(e) {
if (!filteredTags.includes(e.target.innerHTML)){
filteredTags.push(e.target.innerHTML);
} else {
filteredTags = filteredTags.filter(function(elem){
return elem != e.target.innerHTML;
})
}
// setFilteredCards(filteredTags)
}
If I console.log filteredTags at the end of the function, I get the expected result (tags are included or removed from the list).
But when I try to add setFilteredCards()
(removing comment on the line) and console.log the values, I get that:
What am I doing wrong? How do I fix this?
Upvotes: 0
Views: 52
Reputation: 1422
This is because whenever setFilteredCards is triggered it will cause your state to update and component will rerender which is why your stored value in filteredTags is reinitiated once again.
function Homepage() {
const [cards, setCards] = useState([]);
const [filteredCards, setFilteredCards] = useState([]);
const [filteredTags,setFilteredTags] = useState([]);
function toggleSingleTag(e) {
if (!filteredTags.includes(e.target.innerHTML)){
setFilteredTags((ft)=>[...ft,e.target.innerHTML])
//filteredTags.push(e.target.innerHTML);
} else {
setFilteredTags((ft)=>{return ft.filter(function(elem){
return elem != e.target.innerHTML;
})
})
/*filteredTags = filteredTags.filter(function(elem){
return elem != e.target.innerHTML;
})*/
}
// setFilteredCards(filteredTags)
}
Upvotes: 0
Reputation: 218837
filteredTags
is declared and defined as a new empty array with each component render:
let filteredTags = [];
If you want the value to persist across renders, that's what state is for:
const [filteredTags, setFilteredTags] = useState([]);
Just like with your other state values, this will define it as an empty array on the first render and allow you to update state with each render. For example, instead of this:
filteredTags.push(e.target.innerHTML);
You would update the state value:
setFilteredTags([...filteredTags, e.target.innerHTML]);
And instead of this:
filteredTags = filteredTags.filter(function(elem){
return elem != e.target.innerHTML;
})
You would update the state value:
setFilteredTags(filteredTags.filter(function(elem){
return elem != e.target.innerHTML;
}));
Basically, plain local variables are useful as helpers only for that render. Anything that should be maintained across renders belongs in state.
Upvotes: 1