Home > Mobile >  React Native - useState doesn't work in useEffect function
React Native - useState doesn't work in useEffect function

Time:08-28

I'm a beginner in react-native and i don't understand the problem in this stuff :

in App.js

import React, { useEffect, useState } from 'react';
import { ActivityIndicator, FlatList, Text, View } from 'react-native';

export default App = () => {
  const [isLoading, setLoading] = useState(true);
  const [isConnected, setisConnected] = useState(false)
  const [data, setData] = useState([]);

  const getMovies = async () => {
     try {
      const response = await fetch('https://reactnative.dev/movies.json');
      const json = await response.json();
      setData(json.movies);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    console.log("before ",isConnected);
    setisConnected(true)
    console.log("after ",isConnected);
  }, []);

  return (
    <View style={{ flex: 1, padding: 24 }}>
      {isLoading ? <ActivityIndicator/> : (
        <FlatList
          data={data}
          keyExtractor={({ id }, index) => id}
          renderItem={({ item }) => (
            <Text>{item.title}, {item.releaseYear}</Text>
          )}
        />
      )}
    </View>
  );
};

Terminal output:

Android Bundling complete 110ms
Android Running app on Infinix X657B
before  false
after false

I pick the code on https://reactnative.dev/docs/network and i tried an idea and result on this but i don't understand why it is not working or where is the error. May it's me who doesn't know well React but this stuff should work

CodePudding user response:

Saying useState is asynchronous is a little misleading, as if it was really async, you could wait for it to finish and then use the value (but you can't).

What causes this is that react takes a snapshot of the state on every render, so all the functions that run during that render can only access one value of isConnected since that's the value that exists in the snapshot, and future values will only be accessible in future renders.

Therefore it's suggested that you use the value directly instead of setting it in a state and then accessing the state, or you could store the value using useRef instead which always returns the most recent value (but will not trigger rerenders if changed)

It's recommended that you try to avoid useEffect in cases like this, if you wanna console.log() something, just log it when you get the value, no need to put it in state, then trigger an effect, and then log it.

CodePudding user response:

React useState is asynchronous in nature. So if you immediately check the value of isConnected it will still be the same as the state update will be handled asynchronously. You could add another useEffect to see if its changing like so:

  useEffect(() => {
    console.log("before ",isConnected);
    setisConnected(true)
    console.log("after ",isConnected);
  }, []);

  // This acts as a callback function that 
  //   we pass to setState https://reactjs.org/docs/react-component.html#setstate
  useEffect(() => {
    console.log("isConnected value ",isConnected);
  }, [isConnected]);
  • Related