When updating your state using hooks, it's best to use callbacks.

Try updating your code:

setNames(prevNames => [...prevNames, ...newNames])

This works in the same way that prevState worked with setSate().

On to your solution, you can set the initial state within useState():

const array = [
  {
    age: 13,
    name: "Housing"
  },
  {
    age: 23,
    name: "Housing"
  }
];

const [names, setNames] = useState(() => array.map(item => item.name));

useEffect(() => {
  console.log(names);
}, []);
Answer from Joss Classey on Stack Overflow
Top answer
1 of 4
13

When updating your state using hooks, it's best to use callbacks.

Try updating your code:

setNames(prevNames => [...prevNames, ...newNames])

This works in the same way that prevState worked with setSate().

On to your solution, you can set the initial state within useState():

const array = [
  {
    age: 13,
    name: "Housing"
  },
  {
    age: 23,
    name: "Housing"
  }
];

const [names, setNames] = useState(() => array.map(item => item.name));

useEffect(() => {
  console.log(names);
}, []);
2 of 4
7

You should have the useEffect() subscribe to both the contentLoading and array props, so it runs whenever there is a change to either, instead of running a single-time after the first mount.

Working code and sandbox: https://codesandbox.io/s/mutable-mountain-wgjyv

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const array = [
  {
    age: 13,
    name: "Housing"
  },
  {
    age: 23,
    name: "Housing"
  }
];

const App = () => {
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      setLoading(true);
    }, 2000);
  }, []);

  return <Child array={array} contentLoading={loading} />;
};

const Child = ({ array, contentLoading }) => {
  const [names, setNames] = useState([]);
  useEffect(() => {
    createArray();
  }, [contentLoading, array]);

  const createArray = () => {
    if (contentLoading) {
      const newNames = array.map(item => item.name);
      setNames([...names, ...newNames]);
    }
  };

  return (
    <div>
      {names.map(name => (
        <div>{name}</div>
      ))}
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Discussions

React useState() array not updating
I have created new custom selectbox using React. There is pre-populated array which I am loading on component load (using useEffect). When user search for any non existing country there would be a ... More on stackoverflow.com
🌐 stackoverflow.com
useState to update an array does not work
I am trying to update the array using useEffect + useState. const CategorySearch = (props) => { const initialValue = [ { value: '', name: '', }, ]; const [options, setOptions] = useState(initialValue); const updateOptions = () => { let convert = []; for (const options of props.categories) { ... More on forum.freecodecamp.org
🌐 forum.freecodecamp.org
1
0
July 17, 2020
updating array with useState and rendering with useEffect
Also when appending to an array using set state, you need to use the callback to get the current value: setNoteList((existingNotes) => […existingNotes, noteObj]) More on reddit.com
🌐 r/reactjs
19
17
December 10, 2022
Need help with useState hook - can't update an array using the spread operator
Both versions look like they should work -- maybe it's something in the surrounding context? Can you share more and/or repro in a codepen? More on reddit.com
🌐 r/reactjs
9
2
December 5, 2021
🌐
TechNetExperts
technetexperts.com › home › react usestate array not updating: a common problem [solved]
React useState array not updating: A common problem [SOLVED]
November 13, 2025 - This can help to avoid errors and unexpected behavior in your code. To use immutable state with useState arrays, we can use the spread operator (…) to create a copy of the array before modifying it. Then we can update the state with the copy.
Top answer
1 of 3
8

The problem appears to be that you're passing to useState() the array (updatedVal) that has its reference unchanged, thus it appears to React that your data hasn't been modified and it bails out without updating your state.

Try drop that unnecessary variable and do directly setCountries([...countries, obj])

Another minor fix about your code I may suggest: you may use Array.prototype.every() to make sure that every existing item has different label. It has two advantages over .filter() - it will stop looping right upon hitting duplicate (if one exists) and won't proceed till the end of array (as .filter() does), thus won't slow down unnecessarily re-render and it returns boolean, so you won't actually need extra variable for that.

Following is a quick demo of that approach:

const { useState, useEffect } = React,
      { render } = ReactDOM,
      rootNode = document.getElementById('root')
      
const CountryList = () => {
  const [countries, setCountries] = useState([])
  
  useEffect(() => {
    fetch('https://run.mocky.io/v3/40a13c3b-436e-418c-85e3-d3884666ca05')
      .then(res => res.json())
      .then(data => setCountries(data))
  }, [])
  
  const addCountry = e => {
    e.preventDefault()
    const countryName = new FormData(e.target).get('label')
    if(countries.every(({label}) => label != countryName))
      setCountries([
        ...countries,
        {
          label: countryName,
          value: countries.length+1
        }
      ])
    e.target.reset()
  }
  
  return !!countries.length && (
    <div>
      <ul>
        {
          countries.map(({value, label}) => (
            <li key={value}>{label}</li>
          ))
        }
      </ul>
      <form onSubmit={addCountry}>
        <input name="label" />
        <input type="submit" value="Add country" />
      </form>
    </div>
  )
}

render (
  <CountryList />,
  rootNode
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

2 of 3
2

I have found the root problem. In your Select Box component you have:

 const [defaultValueoptions, setdefaultValueoptions] = useState(options);

It should be:

 const [defaultValueoptions, setdefaultValueoptions] = useState([]);

  useEffect(() => {
    setdefaultValueoptions(options);
  }, [options]);
🌐
freeCodeCamp
forum.freecodecamp.org › t › usestate-to-update-an-array-does-not-work › 410244
useState to update an array does not work - The freeCodeCamp Forum
July 17, 2020 - I am trying to update the array using useEffect + useState. const CategorySearch = (props) => { const initialValue = [ { value: '', name: '', }, ]; const [options, setOptions] = useState(initialValue); const updateOptions = () => { let convert = []; for (const options of props.categories) { convert.push({ value: options._id, label: options.name }); } console.log(convert); setOptions(convert); console.log(options); }; useEffect(() ...
🌐
React
react.dev › reference › react › useState
useState – React
If you need to use the next state, you can save it in a variable before passing it to the set function: ... React will ignore your update if the next state is equal to the previous state, as determined by an Object.is comparison.
🌐
Reddit
reddit.com › r/reactjs › updating array with usestate and rendering with useeffect
r/reactjs on Reddit: updating array with useState and rendering with useEffect
December 10, 2022 -

It's my first personal project and I'm stuck with two problems. I already tried a lot of different things, watched videos, and checked some codes, but still, nothing worked. I feel like it's something very basic that I'm forgetting.

The project is a Notepad app, a very simple one that I intend to add more features to later on.

However, every time my "send" button is clicked, the value doesn't get saved, it only shows up in the array on the second click.

Then, my list of 'Saved Notes' won't render the new note when "send" is clicked, only when I reload the page. I haven't been successful in using useEffect for this.

pages/home.jsx

import NotePad from "../Components/NotePad";
import StickNotes from "../Components/StickNotes";

export default function Home() {
  return (
    <main>
      Note Padding
      <NotePad />
      <StickNotes />
    </main>
  )
}

------

components/NotePad.jsx

import { useState } from 'react';

export default function NotePad() {
  const [title, setTitle] = useState('')
  const [note, setNote] = useState('')
  const [noteList, setNoteList] = useState([])

  function submitNote() {
    const noteObj = {
      id: Math.random(),
      title,
      note
    }

    setNoteList([...noteList, noteObj])

    localStorage.setItem('noteList', JSON.stringify(noteList))

    setNote('')
    setTitle('')
  }

  return (
    <form>
      <input
        label="note-title"
        placeholder="Note Title"
        type="text"
        value={title}
        onChange={ (e) => setTitle(e.target.value) }
      />
      <input
        label="note-text"
        placeholder="Write your note here"
        type="text"
        value={note}
        onChange={ (e) => setNote(e.target.value) }
      />
      <button
        type="button"
        onClick={ () => submitNote() }
      >
        Send
      </button>
    </form>
  )
}

-------

components/StickNotes.jsx

export default function StickNotes() {
  const list = JSON.parse(localStorage.getItem('noteList'))

  return (
    <div>
      { list && (list
        .map(note => (
          <div key={ note.id }>
            <h1>{ note.title }</h1>
            <div>{ note.note }</div>
          </div>
        )))
      }
    </div>
  )
}
demonstration
Top answer
1 of 5
14
Also when appending to an array using set state, you need to use the callback to get the current value: setNoteList((existingNotes) => […existingNotes, noteObj])
2 of 5
5
There's a lot of bad info in this thread. First of all, your error was caused by the fact that you're passing in noteList to .setItem which refers to the original value stored in state, not the updated one. This is not because setState is asynchronous (it is) but simply because the value returned by it will only be updated in the next render, which will also cause your function to be recreated, etc. You're capturing the old value in scope of your update function. A comment mentioned that your item will not be updated from localStorage. This is false. The StickNotes component will re-render every time the parent component rendered, regardless of whether you passed in any props to it. This is a common misconception about React most people have and it may be due to the name, where one might assume it's a reactive framework, when in reality it isn't. The LocalStorage web API is also synchronous, which means your update will have applied to localStorage by the time this child runs its render cycle. To circumvent this behaviour, you can use the memo function to wrap this component, and you'll quickly notice that your notes will stop updating altogether. Should you use localStorage at all? I'd say no. If you must use it to store previous entries, you should try to avoid accessing it in the render cycle. This is because as I've mentioned it's a synchronous API that potentially reads from disc, which means it can be incredibly slow and having it in a hot path such as a render function is going to cause a lot of lag as your application grows. Another issue with how you use localStorage is that it's out of sync with your UI. When you refresh you'll see the notes from the final update before refresh but as soon as you add one, it will show only that new one. If you want to bind data to localStorage your approach should be to: Create a custom hook with a meaningful name so that you understand the abstraction later on. Access the localStorage only once when your hook first runs. Save the current value in state as the initial value of that state. On update, you should use setState to propagate changes to the rest of the UI To store the latest value in localStorage you should spawn a new task (setTimeout or push it to the next animation frame by using requestAnimationFrame) so that it doesn't block your render and call .setItem inside a callback to that. Something tells me you're a beginner or are new to React and so what I'd recommend is not to reach for localStorage at all until you have a firm grasp of other concepts discussed in this thread. It doesn't immediately play well with React, therefore I'd recommend adding it as an enhancement later on.
Find elsewhere
🌐
YouTube
youtube.com › life with js
React useState array update not updating the UI fix, implementation of react array state #Shorts - YouTube
The fix of the problem react useState array item, when we put array item in react state and try to change its value and set the new value to react state usin...
Published   February 12, 2022
Views   5K
🌐
Reddit
reddit.com › r/reactjs › need help with usestate hook - can't update an array using the spread operator
r/reactjs on Reddit: Need help with useState hook - can't update an array using the spread operator
December 5, 2021 -

I am fairly new to React and I think I am missing an important concept about state.

I am trying to update a state variable, specifically an array. The following function successfully updates the array if I use Array.push(), but not if I use destructuring/the spread operator. What am I missing? Also, the template is completely non-reactive - even when the console.log statement displays the correct value, the HTML does not.

function MyComponent() {
    const [selection, setSelection] = useState([]);

    const handleSelection = (id) => {
        // doesn't work
        // let newSelection = [...selection, id];

        let newSelection = selection;
        newSelection.push(id);

        // Prints the correct value when using Array.push() but not destructuring
        console.log(selection);

        setSelection(newSelection);
    };

    return (
        {/* never changes */}
        <pre>{JSON.stringify(selection, null, 2)}</pre>
    )
}

EDIT: I thought this was a problem with how I was setting state on the selection variable, but it turns out the issue was with other parts of my code that are tangentially related to this. The problem was that I was trying to to loop over some data and generate a component for each datum, but I wasn't doing that correctly. I was setting a different state variable to hold these components, and the various pieces of state were out of sync. Here is a repro of the working code, where I am mapping the components correctly (in the template directly rather than setting state, which seems to be better practice). As you can see, spread/destructuring works perfectly as expected now.

🌐
freeCodeCamp
forum.freecodecamp.org › curriculum help
React useState Help - Update item in Array of Objects - Curriculum Help - The freeCodeCamp Forum
February 8, 2024 - Hello, I’m creating a game where you have to roll ten dice and get their numbers to match. You can reroll the dice and you can click on a die to freeze it (keep it’s number/don’t reroll) I’m storing dice data in a useState that holds an array of objects When I try to update the useState object by directly reversing the die’s isFrozen boolean, it doesn’t work.
🌐
React
react.dev › learn › updating-arrays-in-state
Updating Arrays in State – React
Updating Objects explains what mutation is and why it’s not recommended for state. push() will mutate an array, which you don’t want: App.jsApp.js · ReloadClearFork · import { useState } from 'react'; let nextId = 0; export default function List() { const [name, setName] = useState(''); const [artists, setArtists] = useState([]); return ( <> <h1>Inspiring sculptors:</h1> <input value={name} onChange={e => setName(e.target.value)} /> <button onClick={() => { artists.push({ id: nextId++, name: name, }); }}>Add</button> <ul> {artists.map(artist => ( <li key={artist.id}>{artist.name}</li> ))} </ul> </> ); } Show more ·
🌐
10xdev
10xdev.blog › react-usestate-hook-update-array
Update Arrays with React useState Hook Without Push |
April 24, 2022 - You can’t update the array directly without using the method returned from useState(). In our case, it’s setMyArray(). Now since the state is an array, how to add a new element to the array? Normally, we would use the push() method for adding a new element to an array: ... However, with React, we need to use the method returned from useState to update the array.
🌐
DhiWise
dhiwise.com › post › react-usestate-set-not-working-here-how-to-fix-it
The Fix for React useState Set Not Working
September 5, 2024 - When useState doesn't seem to be setting the state as expected, the first step is to examine how the initial value is assigned and how subsequent updates are made. Check whether the initial state is correctly defined.
🌐
DevGenius
blog.devgenius.io › updating-arrays-and-objects-with-usestate-in-react-what-you-may-not-know-4af169c496c0
Updating Arrays and Objects with useState in React: What you May Not Know
January 19, 2024 - The result is that setState will only update the corresponding Object (“John”), changing every property that differs from the previous state value, and including everything that didn’t exist. That Is It for today, I hope ended up learning a little bit more about how to use the useState Hook in React, and also how to copy complex data in Javascript.
Top answer
1 of 3
8

The problem appears to be that you're passing to useState() the array (updatedVal) that has its reference unchanged, thus it appears to React that your data hasn't been modified and it bails out without updating your state.

Try drop that unnecessary variable and do directly setCountries([...countries, obj])

Another minor fix about your code I may suggest: you may use Array.prototype.every() to make sure that every existing item has different label. It has two advantages over .filter() - it will stop looping right upon hitting duplicate (if one exists) and won't proceed till the end of array (as .filter() does), thus won't slow down unnecessarily re-render and it returns boolean, so you won't actually need extra variable for that.

Following is a quick demo of that approach:

const { useState, useEffect } = React,
      { render } = ReactDOM,
      rootNode = document.getElementById('root')
      
const CountryList = () => {
  const [countries, setCountries] = useState([])
  
  useEffect(() => {
    fetch('https://run.mocky.io/v3/40a13c3b-436e-418c-85e3-d3884666ca05')
      .then(res => res.json())
      .then(data => setCountries(data))
  }, [])
  
  const addCountry = e => {
    e.preventDefault()
    const countryName = new FormData(e.target).get('label')
    if(countries.every(({label}) => label != countryName))
      setCountries([
        ...countries,
        {
          label: countryName,
          value: countries.length+1
        }
      ])
    e.target.reset()
  }
  
  return !!countries.length && (
    <div>
      <ul>
        {
          countries.map(({value, label}) => (
            <li key={value}>{label}</li>
          ))
        }
      </ul>
      <form onSubmit={addCountry}>
        <input name="label" />
        <input type="submit" value="Add country" />
      </form>
    </div>
  )
}

render (
  <CountryList />,
  rootNode
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

2 of 3
2

I have found the root problem. In your Select Box component you have:

 const [defaultValueoptions, setdefaultValueoptions] = useState(options);

It should be:

 const [defaultValueoptions, setdefaultValueoptions] = useState([]);

  useEffect(() => {
    setdefaultValueoptions(options);
  }, [options]);
🌐
freeCodeCamp
forum.freecodecamp.org › curriculum help
React useState not updating the variable - Curriculum Help - The freeCodeCamp Forum
April 14, 2023 - Problem There is no syntax errors. Function parseLocalStorage returns a object White using setStorage(parseLocalStorage()) at useState Storage does’nt get modified setStorage used in other functions (like { const [hasParsed , setH...
🌐
YouTube
youtube.com › watch
Solving the Issue of useState Array Not Updating in React - YouTube
Discover how to effectively manage state updates in React using the `useState` hook for arrays without running into infinite rendering issues.---This video i...
Published   April 14, 2025
Views   0