Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialBrandon Benefield
7,739 PointsSOLVED: React + Axios: Getting a Cannot read property error
I am creating a simple weather app using the OpenWeatherMAP API. I'm getting an error when trying to access a property that is deeper than the first level of the list
array in the JSON. I can console.log()
the property and it returns the correct value, but when trying to use it as a prop
is when I experience the error. Now I can render the values of anything inside list
as long as it's not another object. So id
and name
are safe. But going into main
or coord
for example will return undefined
when trying to render the value but will return the correct value if I console.log()
it.
JSON
{
message: "accurate",
cod: "200",
count: 1,
list: [
{
id: 4166776,
name: "Ocoee",
coord: {},
main: {
temp: 304.15,
pressure: 1010,
humidity: 58,
temp_min: 304.15,
temp_max: 304.15
},
}
]
}
index.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import axios from 'axios';
import Header from './modules/Header';
import Input from './modules/Input';
import Weather from './modules/Weather';
import './style.css';
class App extends Component {
constructor() {
super();
this.state = {
weather: []
};
}
getWeather = query => {
axios.get(`https://api.openweathermap.org/data/2.5/find?q=Ocoee&appid=<API KEY>`)
.then(response => {
this.setState({
weather: response.data.list[0]
});
console.log(response.data.list[0]); //returns JSON correctly
console.log(this.state.weather.main.temp); //returns correct value (304.15)
})
.catch(error => {
console.log('Error', error);
});
};
queryWeather = (event) => {
if (event.key === 'Enter') {
event.preventDefault();
this.getWeather();
}
}
render() {
return (
<div className='content'>
<Header />
<Input queryWeather={this.queryWeather} />
<Weather
city={this.state.weather.name}
temp={this.state.weather.main.temp} //this is where the problem is
/>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Weather.js
import React from 'react';
import PropTypes from 'prop-types';
const Weather = props =>
<div>
<p>{props.city}</p> //returns correct city name
<p>{props.temp}</p> //should return temperature but is undefined
</div>
export default Weather;
SOLVED:
Just in case someone stumbles upon this, I have this solved. It may not be the best solution but it works. All I did was add some more empty arrays to my state
object and populate them with values from the JSON
.
index.js
this.state = {
weather: [],
temp: [], //gets info from response.data.list[0].main.temp
clouds: [] //gets info from response.data.list[0].weather[0].description
};
}
getWeather = query => {
axios.get(`https://api.openweathermap.org/data/2.5/find?q=${query}&units=imperial&appid=f92c1f4990b0574d4a4e4d3dd556f388`)
.then(response => {
this.setState({
weather: response.data.list[0],
temp: response.data.list[0].main.temp, //pushes data to this.state.temp
clouds: response.data.list[0].weather[0].description //pushes data to this.state.clouds
});
})
.catch(error => {
console.log('Error', error);
});
};
Anders Blom
9,124 PointsAnders Blom
9,124 PointsAnother way of doing this (and for scalability) is to pass the entire
response.data.list[0]
object to <Weather /> as props (<Weather weatherData={this.state.weather} />
, and access the keys of that object withthis.props.weatherData.main.temp
for example.In your index.js
render()
method you can also check to see if thethis.state.weather
-object is undefined or not, and render based on this fact. This should stop the error, and even give you a chance to create a loader/spinner/display errors if the API is unavailable, and whatnot:Of course, if you want to take this further, React 16 introduced Error Boundaries, so this can be done in an even better way that assures that only "parts" of your app will throw errors and not discard the entire app because of a small error in a child-component somewhere. You can read more about Error Boundaries here: https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html