kyw
kyw

Reputation: 7533

Initial values in useState not updated after re-render

Pretty sure I'm missing something fundamental about React.

So here's the code:

export function EditTagsModal({existingTags}) {
  console.log('existingTags', existingTags);

  const [selectedTags, setSelectedTags] = React.useState(existingTags);

  console.log('selectedTags:', selectedTags);
  ...
}

In a parent component, <EditTagsModal /> is consumed like this:

{tags && <EditTagsModal existingTags={tags} /> }

Here is how it goes down:

  1. existingTags starts with, say, ['hello']
  2. setSelectedTags is doing its thing.
  3. selectedTags is now ['hello', 'world', 'world'].
  4. Then I send tags to server, close modal, parent re-render.
  5. Now the tags returned by server is ['hello', 'world'], without the duplicates.
  6. Here's the thing: Now I open the modal again, I'm still seeing my values in selectedTags(in that second console.log above) that has the duplicates, not the tags(the first console.log) from my server.

What's up with react?

Upvotes: 5

Views: 4935

Answers (1)

Drew Reese
Drew Reese

Reputation: 202605

The selectedTags state in the useState hook is only initialized once.

If tags remains a truthy defined array (even empty arrays are truthy and defined) then the EditTagsModal component remains mounted by {tags && <EditTagsModal existingTags={tags} />}. If the tags value, and thus the existingTags prop updates and EditTagsModal is rerendered, then you should implement an useEffect hook with a dependency on the existingTags prop to update the local state when the prop value updates.

useEffect(() => {
  setSelectedTags(existingTags);
}, [existingTags]);

useEffect with a dependency array is synonymous to a class component's componentDidMount and componentDidUpdate lifecycle methods.

Upvotes: 5

Related Questions