Hello I am having some trouble with removing items from selectedTags state array onClick. Please see the below react component:
TagPosts.tsx
interface Tag {
id: string;
name: string;
}
const TagPosts: React.FC= () => {
let [tags, setTags] = useState<Tag[]>([]);
let [selectedTags, setSelectedTags] = useState<Tag[]>([]);
// STATE IS BEING UPDATED FINE WITH THE BELOW addToSelected FUNCTION
const addToSelected = (tag: Tag) => {
setSelectedTags([...selectedTags, tag]);
};
// HAVING ISSUE WITH REMOVING ITEMS FROM SELECTED ARRAY. STATE IS NOT BEING UPDATED WITH THE BELOW FUNCTION
const removeFromSelected = (tag: Tag) => {
const index = selectedTags.indexOf(tag);
const newSelectedTags = selectedTags;
newSelectedTags.splice(index, 1);
setSelectedTags(newSelectedTags);
};
const renderTags = tags.map((tag) => {
if (!selectedTags.includes(tag)) {
return (
<StyledTagBox key={tag.id} onClick={() => addToSelected(tag)}>
<Typography variant="displayTags">{tag.name}</Typography>
</StyledTagBox>
);
} else if (selectedTags.includes(tag)) {
return (
<SelectedTagBox key={tag.id} onClick={() => removeFromSelected(tag)}>
<Typography variant="displayTags" color="#fff">
{tag.name}
</Typography>
</SelectedTagBox>
);
}
});
export default TagPosts;
Can anyone spot the bug? The weird thing is that when i console.log the newSelectedTags variable it is showing the desired array but the setSelectedTags function in the line right after is not executing?
Any help would be greatly appreciated. Thanks!
CodePudding user response:
React's state is immutable, and only checks reference equality.
The problem with your code is splice
does not change the state reference.
You can use filter
which is very common in React's array update. It will do 2 things:
- Remove items according to your condition
- Create a new array that makes React understand state update
const removeFromSelected = (tag: Tag) => {
const newSelectedTags = selectedTags.filter(currentTag => currentTag !== tag);
setSelectedTags(newSelectedTags);
};
CodePudding user response:
Ah I had this problem plenty of times. The issue is with the rendering of the state.
Since you are copying selectedTags
directly using const newSelectedTags = selectedTags;
, the state hook thinks that nothing has changed. It is a very annoying feature but should be solved if you instead do something like:
newSelectedTags = [...selectedTags]
(A shallow copy as caTS suggested)