Home > Mobile >  Problem of state undefined in useEffect function
Problem of state undefined in useEffect function

Time:04-07

I have a problem with my useEffect, I think it's due to the asynchronous functions inside but I don't know how to fix the problem. Let me explain: in my useEffect, I have a function that is used to retrieve user data thanks to the AsyncStorage and I want that in a weather API request I can enter the user's city as a parameter so it works on the spot but when I reload the application it gives me an error message like : currentUserData.user.city is undefined

Here is the code :

  const [loading, setLoading] = useState(false);
  const [currentData, setCurrentData] = useState({});
  const [currentUserData, setCurrentUserData] = useState({});
  const navigation = useNavigation();
  
  useEffect(() => {
    setLoading(true);
    const getUserData = async () => {
      try {
        const jsonValue = await AsyncStorage.getItem('user');
        setCurrentUserData(JSON.parse(jsonValue));
        const response = await axios.get(
          `https://api.weatherapi.com/v1/current.json?key=${APIKEY}&q=${currentUserData.user.city}&aqi=no&lang=fr`,
        );
        setCurrentData(response.data.current.condition);
        setLoading(false);
      } catch (e) {
        setLoading(false);
        alert(e);
      }
    };
    getUserData();
  }, []);
  
  if (loading) {
    return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
        <Text
          style={{
            fontSize: 80,
            color: 'red',
          }}>
          Loading...
        </Text>
      </View>
    );
  } else {
    return (
      <View style={styles.container}>
        <View style={styles.content}>
          <View
            style={{
              flexDirection: 'row',
              justifyContent: 'space-between',
              alignItems: 'center',
              marginTop: 50,
            }}>
            <View
              style={{flexDirection: 'column', marginLeft: 20, marginTop: 20}}>
              <Image
                style={{width: 50, height: 50}}
                source={{
                  uri: `https:${
                    Object.keys(currentUserData).length > 0
                      ? currentData.icon
                      : ''
                  }`,
                }}
              />
            </View>
            <Text style={styles.title}>
              Bienvenue, {'\n'}{' '}
              <Text style={{fontWeight: 'bold'}}>
                {Object.keys(currentUserData).length > 0
                  ? currentUserData.user.first_name
                  : ''}
              </Text>
            </Text>
            <TouchableWithoutFeedback
              onPress={() => navigation.navigate('UserScreen')}>
              <FontAwesomeIcon
                style={{marginRight: 20, marginTop: 20}}
                size={35}
                icon={faUser}
              />
            </TouchableWithoutFeedback>
          </View>
        </View>
      </View>
    );
  }
}

CodePudding user response:

Please use ? operator to access the currentUserData.user. e.g.currentUserData?.user?.city.

Because initial state is {}, so currentUserData.user is undefined and your code tried to get value from undefined.

And use in your API URL.

First please write a console. And try to use the following code.

`https://api.weatherapi.com/v1/current.json?key=${APIKEY}&q=${currentUserData? currentUserData?.user?.city || '' : ''}&aqi=no&lang=fr`

Your mistake is that you used the state variable as soon as calling setCurrentUserData. We can't use it in this way. Updated hook is following:

useEffect(() => {
    setLoading(true);
    const getUserData = async () => {
      try {
        const jsonValue = await AsyncStorage.getItem('user');
        const parsedUserData = JSON.parse(jsonValue) || {};
        setCurrentUserData(parsedUserData);
        const response = await axios.get(
          `https://api.weatherapi.com/v1/current.json?key=${APIKEY}&q=${parsedUserData?.user?.city}&aqi=no&lang=fr`,
        );
        setCurrentData(response.data.current.condition);
        setLoading(false);
      } catch (e) {
        setLoading(false);
        alert(e);
      }
    };
    getUserData();
  }, []);

CodePudding user response:

I think you might misuse of React Hook, setCurrentUserData update the state asynchronously, immediately use currentUserData.user.city is completely wrong, thus you either use option below:

  1. Use data returned from AsyncStorage
const jsonValue = await AsyncStorage.getItem('user');
const userData = JSON.parse(jsonValue)
setCurrentUserData(userData);
const response = await axios.get(
     `https://api.weatherapi.com/v1/current.json?key=${APIKEY}&q=${currentUserData.user.city}&aqi=no&lang=fr`,
);

  1. Remove logic all below setCurrentUserData(JSON.parse(jsonValue));, and move them into another useEffect with currentUserData as dependency
useEffect(() => {
    if(currentUserData) {
        // make api request here
        const response = await axios.get(
          `https://api.weatherapi.com/v1/current.json?key=${APIKEY}&q=${currentUserData.user.city}&aqi=no&lang=fr`,
        );
    
// some logic here...
    }
}, [currentUserData])
  • Related