Home > Blockchain >  Referencing JSON object fields after assigning to variable in useEffect()
Referencing JSON object fields after assigning to variable in useEffect()

Time:10-25

I'm attempting to retrieve a JSON object from an API call, and then set a useState variable to the response for use in my app. I am able to successfully receive the JSON response, but if I try to reference specific fields I get an error saying null is not an object (evaluating data.type). I understand that this happens because initially the data variable is simply null, but I'm not sure the best way to go about preventing this and I suspect I'm doing something fundamentally wrong.

Here's the function which queries the API and retrieves the response data:

export function searchFlightOffers(postData) {
    return getAmadeusToken().then(data => {
        const config = {
            headers: {
                'Authorization': `Bearer ${data.access_token}`
            }
        }

        return axios.post("https://test.api.amadeus.com/v2/shopping/flight-offers", postData, config).then(data => data);
    });
    
}

Then the React Native function which uses it

export default function FlightScreen() {
  const [flightResponse, setFlightResponse] = useState(null);

  useEffect(() => {
    searchFlightOffers(postData).then(data => setFlightResponse(data.data));
  }, [])

  console.log("TEST: ", flightResponse.type);

Is there a more efficient way I should be doing this?

EDIT: To add hopefully a more clear description of the issue, here's the JSX I'm trying to use this data in:

    return (
        <ScrollView style={{marginTop: 220}}>
        {
            flightResponse != null ? flightResponse.map(data => {
                return (
                    <FlightCard
                        key={data.id}
                        data={data}
                        onPress={() => {}}
                    />
                )
            }) : false
        }
        </ScrollView>

If I add a conditional which checks to see if the flightResponse data is null and then map the data if not then this works just fine. Removing the conditional and just leaving it like this:

    return (
        <ScrollView style={{marginTop: 220}}>
        {
            flightResponse.map(data => {
                return (
                    <FlightCard
                        key={data.id}
                        data={data}
                        onPress={() => {}}
                    />
                )
            })
        }
        </ScrollView>

Leaves me with this error: null is not an object (evaluating 'flightResponse.map') .

While technically the conditional is a solution to my problem there must be a cleaner way to handle this no?

Update: A solution to this problem is to change

const [flightResponse, setFlightResponse] = useState(null);

to

const [flightResponse, setFlightResponse] = useState([]);

and then I can remove the conditional from the JSX.

CodePudding user response:

My apology that I didn't see the additional info you have put there. Apparently you have resolved this issue on your own by adding the check for null, which, to my knowledge, is the correct usage pattern.

You have to check for null because the code in useEffect is not guaranteed to complete (because it is async) before react native executes the code to render the components. By checking for null, you place a guard on this exact situation (and other situations, such as error during fetching data, data itself is empty, etc.).

Original answer (obsolete)

Try rewrite your searchFlightOffers function in async/await style. This way, it is clearer what object is returned. I suspect your current version does not return the data.

The rewrite can be something like this (untested, use with caution).

export const searchFlightOffers = async (postData) => {
    try {
        const token = await getAmadeusToken();
    } catch (err) {
        // handle error during token acquisition
        console.log(err);
    }
    
    const config = {
        headers: {
            'Authorization': `Bearer ${token.access_token}`
        }
    }
    try {
        const flightOfferData = await axios.post(
            "https://test.api.amadeus.com/v2/shopping/flight-offers",
            postData,
            config,
        );
        return flightOfferData;
    } catch (err) {
        // handle error during flight offer acquisition
        console.log(err);
    }
}
  • Related