DEV Community

Undefined Nested Object in REST API with React Hooks?

mitchelln11 on June 04, 2020

Having trouble trying to access nested objects in the OpenWeather REST API. Getting full results in Postman, but not when trying to render. Postma...
Collapse
 
suelopoder profile image
Diego Sisto

It's most likely something silly. Try console.log(openWeather, openWeather.weather, openWeather.weather[0])

Collapse
 
mitchelln11 profile image
mitchelln11

comes back undefined.

Collapse
 
suelopoder profile image
Diego Sisto

You should have 3 outputs. Is that undefined, undefined, undefined?
Can we get the full code?

Thread Thread
 
mitchelln11 profile image
mitchelln11

Unhandled Rejection (TypeError): Cannot read property '0' of undefined. Breaks the page, doesn't even log anything.

Thread Thread
 
suelopoder profile image
Diego Sisto

Can we see the code please? It could be a number of things.

Thread Thread
 
mitchelln11 profile image
mitchelln11

It is in React and uses hooks.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const LocalWeather = () => {
    const [openWeather, setWeather] = useState([]);

    useEffect(() => {
        axiosGet();
    }, []); //  Run once on load

    const axiosGet = () => {
        const data = axios.get(`https://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=${process.env.REACT_APP_WEATHER_KEY}`)
        .then(data => setWeather(data.data));
    console.log(openWeather, openWeather.weather, openWeather.weather[0]);
    }

    return (
        <ul>
            <li>{openWeather.name}</li>
            <li>{openWeather.cod}</li>
            <li>{openWeather.id}</li>
            <li>{openWeather.timezone}</li>
            <li>{openWeather.dt}</li>
            <li>{openWeather.visibility}</li>
            <li>{openWeather.base}</li>
            {/* <li>{openWeather.current.weather[0].main}</li> */}
        </ul>
    );
}

export default LocalWeather;

The console.log in the axiosGet method is breaking the page.

Thread Thread
 
suelopoder profile image
Diego Sisto

Thanks!
Let's change the console.log(openWeather, openWeather.weather, openWeather.weather[0]); to be inside the then callback:

const axiosGet = () => {
      const data = axios.get(`https://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=${process.env.REACT_APP_WEATHER_KEY}`)
      .then(data => {
        setWeather(data.data);
        console.log('Service data was', data.data);
      });
  }

That will give you an idea of what's actually stored in openWeather.

On the other hand, you got a current in the failing line. .current is used for react ref but not for state. Try removing that.

Good luck!

Thread Thread
 
mitchelln11 profile image
mitchelln11

Get the following:

Service data was Array(0)length: 0__proto__: Array(0)

I also removed the current. Thanks, I forgot I had that in there.

Thread Thread
 
suelopoder profile image
Diego Sisto

Seem like you get an empty array. Maybe you are getting an unexpected response, check chrome network console developers.google.com/web/tools/ch...
Maybe you don't need to data.data and just data. Keep console logging =)

Thread Thread
 
mitchelln11 profile image
mitchelln11

So somebody on a Slack channel figured this out for me.

When returning JSX:

<li>{openWeather.weather && openWeather.weather[0].main}</li>
Enter fullscreen mode Exit fullscreen mode

This feels like a bug to me, but it does output the response from the REST API.

I am still getting a warning, which I am unsure why:

    const axiosGet = () => {
        const data = axios.get(`https://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=api-key`)
        .then(data => setWeather(data.data));
    }
Enter fullscreen mode Exit fullscreen mode

It's saying Line 14:15: 'data' is assigned a value but never used no-unused-vars, although everything works. Aren't I setting the rest endpoint to data, and then using it when running the setWeather method?

Thread Thread
 
suelopoder profile image
Diego Sisto • Edited

Great that you figure it out!

Keep in mind that you get a first render before you get the data with openWeather as the default value passed in useState.

Maybe you can:

const LocalWeather = () => {
    const [openWeather, setWeather] = useState(null); // null obj instead of empty array

    useEffect(() => {
        axiosGet();
    }, []); //  Run once on load

    const axiosGet = () => {
        axios.get(`https://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=${process.env.REACT_APP_WEATHER_KEY}`)
        .then(data => setWeather(data.data));
    }

    if (!openWeather) return null; // empty render until we get data

    // if we get here we do have openWeather
    return (
        <ul>
            <li>{openWeather.name}</li>
            <li>{openWeather.cod}</li>
            <li>{openWeather.id}</li>
            <li>{openWeather.timezone}</li>
            <li>{openWeather.dt}</li>
            <li>{openWeather.visibility}</li>
            <li>{openWeather.base}</li>
            {openWeather.weather.map(item => 
              <li key={item.main}>{item.main}</li>
            )}
        </ul>
    );
}

no-unused-vars is because you are doing const data = and never use that data const. Not to be confused with the then data argument. Note I removed it in my example

Thread Thread
 
mitchelln11 profile image
mitchelln11

Sweet, works perfectly, i thought that data was the same thing as in the then argument. Works, no errors! Thank you so much for your help

Thread Thread
 
suelopoder profile image
Diego Sisto

Glad to read that! Keep up the good work!

Thread Thread
 
gustavozapata profile image
Gustavo Zapata

I just spent hours trying to figure out what the issue was. Thanks to you guys (mitchelln11 and Diego Sisto) I was able to fix it.
My two cents:
Instead of if(!openWeather) return null;
I used {!openWeather && openWeather.weather.map(...) which will render the rest of the app and just ignoring this line.