1

I'm using the useState hook to populate items in an array.

const [meals, setMeals] = useState([]);
useEffect(async () =>{
    const mealsData = await fetchMeals(localStorage.getItem('user_id'));
    console.log(mealsData);// Array(3)
    setMeals([...meals, mealsData]);
    console.log(meals);//[]
 }, []);

The array doesn't get copies in my setMeals method, what am I doing wrong here?

Melissa Stewart
  • 3,483
  • 11
  • 49
  • 88

4 Answers4

3

This is because

setMeals([...meals, mealsData]);

is an asynchronous call and you are logging the meals before being sure the state actually updated

console.log(meals);

You should call and check your console.log() function in another useEffect() call which runs on every state change and assures that the state actually changed

useEffect(() => {
    console.log(meals);
 }, [meals]);

[meals] passed as the second argument will let this useEffect() run every time meals (actually) update.

Akshit Mehra
  • 747
  • 5
  • 17
0

the update is asynchronous, the new value is not available immediately as you're expecting. You can find an in-depth explanation here: useState set method not reflecting change immediately

G Gallegos
  • 609
  • 6
  • 11
0

UseEffect cannot be async you should wrap it in an async function

function useMeals() {
   const [meals, setMeals] = useState([]);
    useEffect(() => {
      async function setFetchedMeals() {
        const mealsData = await fetchMeals(localStorage.getItem('user_id'));
        setMeals([...meals, mealsData]);
      }
      setFetchedMeals();
    }, []); // letting the dependency array empty will run the effect only once

  console.log(meals)
  return meals;
}
André Gomes
  • 142
  • 1
  • 6
0

You are actually not doing anything wrong, state updates are not synchronous, so logging meals immediately after updating it will not show the updated value

Use an effect for the meals array to detect when it has actually changed...

useEffect(() => {
    console.log(meals);
}, [meals]);
Kwame Opare Asiedu
  • 2,110
  • 11
  • 13