Home > other >  Initial values in useState not updated after re-render
Initial values in useState not updated after re-render

Time:10-26

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?

CodePudding user response:

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.

CodePudding user response:

As it is alluded to in the comments, useState(existingTags) (or whatever you call it) will only use existingTags on the first render.

During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).

After this, on re-renders the useState function does not change the state based on new changes to the props passed in.

export function EditTagsModal(props) {
  console.log('existingTags', existingTags);
  
  const { existingTags } = props;
  const [selectedTags, setSelectedTags] = React.useState(existingTags);
  useEffect(() => { setSelectedTags](existingTags)}, [existingTags] )


  console.log('selectedTags:', selectedTags);
  ...
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related