0

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!

1
  • 2
    Shallow copy your state: const newSelectedTags = [...selectedTags]; Commented Nov 10, 2022 at 17:05

2 Answers 2

2

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);
  };
Sign up to request clarification or add additional context in comments.

1 Comment

This is the best way: it uses filter to both remove the item AND return a new array.
1

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.