DeveloperApps
DeveloperApps

Reputation: 803

Strange operation of setState with an array inside

I have a situation

const [myMessages, setMyMessages] = useState([])

At some point I call (when downloading data from Firebase)

setMyMessages([...myMessages, newMessage])

I have this state process for the application process (my logs, I display the status of myMessages at various times when the program is running)

useEffect() Objects(myMessages) [{"id":"-M3mdwTZw4EtDhQ3zOU6","content":"Y1"}]

useEffect() Objects(myMessages) [{"id":"-M3mdyF6lQE26V1hpTfu","content":"Y2"}]

useEffect() Objects(myMessages) [{"id":"-M3mdyF6lQE26V1hpTfu","content":"Y2"}]

useEffect() Objects(myMessages) [{"id":"-M3mdyF6lQE26V1hpTfu","content":"Y2"}]

useEffect() Objects(myMessages) [{"id":"-M3mdyF6lQE26V1hpTfu","content":"Y2"},{"id":"-M3me-0bcmdPLZxCKZbT","content":"Y3"}]

The method should retrieve the current State and add a new one Ultimately, they should be Y1, Y2, Y3

Here you can see the strange course of writing to State and ultimately Y1 is omitted

What could be the reason?

EDIT:

Application navigation:

function MainStackNavigator() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name='Main' component={Main} options={{ headerShown: false }} />
      </Stack.Navigator>
    </NavigationContainer>
  )
}

The code is in the Main component so it is in the main application component (except for the App)

Upvotes: 1

Views: 45

Answers (2)

cYee
cYee

Reputation: 2184

Since you mentioned useEffect. Most time, when you have weird outcome is because you may forget to add dependencies in your useEffect query. Happened to the best of us. You can simply change how you setMyMessages or add your state to the dependency array

useEffect(()=>{
 // try set state like this
 setMyMessages((myPreviosState)=>
   [...myPreviosState, newMessage])
},[])

or

 useEffect(()=>{
     // try set state like this
     setMyMessages([...myMessages, newMessage])
    },[myMessages // your dependency])

so the state is updated correct. Why it happened? because useEffect is work in a closure, where they get the snapshot of the first initialization. Further update to it will not be update in the closure. You can read about closure.

I hope this help you.

Upvotes: 1

Ferin Patel
Ferin Patel

Reputation: 3968

Avoid Using setState inside useEffect because it create dependency for useEffect. So create another method for fetching the data and setting the state and call that method from useEffect. By doing this, there will be no dependency and no error;

const fetchAndSetState = () => {
  // perform your task here
}

useEffect(() => {
   fetchAndSetState();
},[])

Upvotes: 0

Related Questions