Reputation: 37
I'm currently developing a website where Team information is retrieved here:
export default class TeamInfo extends React.Component{
constructor(props) {
super(props);
this.state = {
isShow: true,
team: []
};
this.getTeam();
}
getTeam(){
const axios = require("axios");
const team_id = this.props.id;
axios.get(API+'/team/'+ team_id).then(res => {
this.setState({team : res.data})
console.log('inside teaminfo... ' + this.state.team.location.city);
})
}
render() {
return(
<div><h1>{this.state.team.location.city}</h1></div>
)}
}
This is the structure of the team JSON answer:
{
"name": "Barcelona",
"shield": "shield.png",
"location": {
"city": "Barcelona",
"country": "SPAIN"
},
"score": 74626,
}
I'm trying to access team location as this.state.team.location.city
, when I log it in console is shown correctly but Unhandled Rejection (TypeError): Cannot read property 'city' of undefined
is shown in the website.
Any hint or help will be greatly appreciated.
Upvotes: 0
Views: 790
Reputation: 26
You can as well use the new ES2020 chain operator to check if a property is present inside an object like this:
render() {
return (
{this.state.team.map(team => (
{team?.location ?<div><h1>{team.location.city}</h1></div>: null}
))}
);
}
The Chain operator ?. will return undefined
if location
is not found inside team, it returns the object otherwise.
Upvotes: 0
Reputation: 1357
Your team data is initialized in your constructor as below
this.state = {
isShow: true,
team: []
};
This caused the error during the first render, as .team.location.city is undefined. On the second render, it is good after you setState with a new value.
To fix this, you need to check if the value is undefined or set the initial value for location.city in the constructor.
render() {
return(
<div><h1>{typeof this.state.team.location !== "undefined" && typeof this.state.team.location.city !== "undefined" && this.state.team.location.city}</h1></div>
)}
Upvotes: 1
Reputation: 202836
Given the component code, your state.team
is an array, so you would need to access it using array indices.
this.state.team[0].location.city
OFC, this assumes the array is populated, so use a guard check first to ensure the first element exists.
this.state.team[0] && this.state.team[0].location.city
You can also conditionally render it as well
export default class TeamInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
isShow: true,
team: []
};
this.getTeam();
}
getTeam() {
const axios = require("axios");
const team_id = this.props.id;
axios.get(API + "/team/" + team_id).then(res => {
this.setState({ team: res.data });
});
}
render() {
return this.state.team[0] ? (
<div>
<h1>{this.state.team[0].location.city}</h1>
</div>
) : null;
}
}
And also since it is an array, mapping the result is also a common pattern
export default class TeamInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
isShow: true,
team: []
};
this.getTeam();
}
getTeam() {
const axios = require("axios");
const team_id = this.props.id;
axios.get(API + "/team/" + team_id).then(res => {
this.setState({ team: res.data });
});
}
render() {
return (
{this.state.team.map(team => (
<div>
<h1>{team.location.city}</h1>
</div>
))}
);
}
}
Note:
this.setState({team : res.data})
console.log('inside teaminfo... ' + this.state.team.location.city);
State updates are "asynchronous", the update happens between render cycles, so the console log will only ever log the current state from this render cycle. Log the updated state in a lifecycle function like componentDidUpdate
.
Upvotes: 1