0

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>
    );
  }
}

4
  • the error comes on the first render. loading is false at startup, and page tries to show currentUserData. maybe change if (loading) to if(currentUserData) Commented Apr 7, 2022 at 4:15
  • @eamanola Thanks for your response, I just tested, and the loading remains all the time suddenly Commented Apr 7, 2022 at 4:20
  • what is the value of console.log(jsonValue) is there a user? Commented Apr 7, 2022 at 4:25
  • @eamanola yes there is the data of the connected user, when jsonValue wants to enter in the currentUserData state because I have the impression that at first it works well then when I reload the app it's undefined Commented Apr 7, 2022 at 4:29

2 Answers 2

1

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();
  }, []);
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for your response, it works when i run the app but once i reload it gives me the same error message that it's undefined
which line do you see the error at?
At the line where is this code : const response = await axios.get( 'https://api.weatherapi.com/v1/current.json?key=${APIKEY}&q=${currentUserData.user.city}&aqi=no&lang=fr', ); the error says that currentUserData.user.city is undefined
Thanks but on reload always the same thing, when I save the code I see the weather icon that appears but when I refresh the app: error 400 because the API is unable to retrieve the data associated with the city
Updated the post with the condition logic. For 400 error, this is correct. So you need to first set the currentUserData with another API because this API may return 400 error.
|
1

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])

2 Comments

Thanks for your response! The problem was solved by Liki Crus but your post can really help thanks !
Glad to hear that!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.