I am retrieving JSON data from an API and then storing it in state and when I try to access the data using this.state
(eg i write this.state.DetailData.title
) it works fine but when I try to access the nested data (eg this.state.DetailData.location.address
) of the same object it throws me an error:
TypeError: Cannot read property 'address' of undefined
Here is my code:
import React from 'react'
import Caro from './Carousel'
import {
Container,
Row,
Col
} from 'reactstrap';
class Detail extends React.Component {
constructor(props)
{
super(props)
this.state = {
DetailData: []
}
}
ponentDidMount() {
fetch('', {
method: 'GET'
})
.then((response) => response.json())
.then((data) => {
this.setState({
DetailData: data.response
})
console.log(typeof(this.state.DetailData));
})
}
render() {
return (
<div>
<Caro / >
<Container >
<Row >
<Col xs = "12" sm = {{size: 8, offset: 2 } md = {{size: 8, offset: 2}} >
< div >
<h1> {this.state.DetailData.title} <h1>
<h1> {this.state.DetailData.location.address} </h1> {/*getting error here*/}
<hr/>
<h6> {this.state.DetailData.description} </h6>
</div>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Detail;
I am retrieving JSON data from an API and then storing it in state and when I try to access the data using this.state
(eg i write this.state.DetailData.title
) it works fine but when I try to access the nested data (eg this.state.DetailData.location.address
) of the same object it throws me an error:
TypeError: Cannot read property 'address' of undefined
Here is my code:
import React from 'react'
import Caro from './Carousel'
import {
Container,
Row,
Col
} from 'reactstrap';
class Detail extends React.Component {
constructor(props)
{
super(props)
this.state = {
DetailData: []
}
}
ponentDidMount() {
fetch('https://api.kloh.in/kloh/external/v1/activity/AID180917200010526C8LFJ4MEIE9CWGXZG4', {
method: 'GET'
})
.then((response) => response.json())
.then((data) => {
this.setState({
DetailData: data.response
})
console.log(typeof(this.state.DetailData));
})
}
render() {
return (
<div>
<Caro / >
<Container >
<Row >
<Col xs = "12" sm = {{size: 8, offset: 2 } md = {{size: 8, offset: 2}} >
< div >
<h1> {this.state.DetailData.title} <h1>
<h1> {this.state.DetailData.location.address} </h1> {/*getting error here*/}
<hr/>
<h6> {this.state.DetailData.description} </h6>
</div>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Detail;
Share
Improve this question
edited Sep 20, 2018 at 13:43
Collin ter Steege
5235 silver badges17 bronze badges
asked Sep 20, 2018 at 13:38
Hadi MirHadi Mir
5,1532 gold badges32 silver badges33 bronze badges
6
- Can you do console.log(this.state.DetailData); and share the data – Hemadri Dasari Commented Sep 20, 2018 at 13:40
-
log the data to see if you are not misspelling something or even if the property
location.address
is exists or not ???? – amdev Commented Sep 20, 2018 at 13:42 - The whole DetailData object is displayed – Hadi Mir Commented Sep 20, 2018 at 13:42
- @hadi could you add the JSON or console output to the question please? – stef Commented Sep 20, 2018 at 13:45
- You need to wait for the ponent to fetch data before using it in the render method. Try to add a flag variable isLoaded to state having default value set to false and then set it to true once the data is fetched in the ponentDidMount method and then conditionally render bases on that isLoaded . Read the link – Sumit Parkash Commented Sep 20, 2018 at 13:51
5 Answers
Reset to default 7When the ponent is mounted your data are not yet fetched so the this.state.DetailData is an empty object and the this.state.DetailData.location is indeed undefined.
To solve this problem you can try checking if the object exists before displaying it. Something like this:
{this.state.DetailData.location ? this.state.DetailData.location.address : ""}
You should also check why you define the DetailData as an array when you initialise your ponent but seem to be expecting an object instead.
this.state = {
DetailData: [] // this should be DetailData: {} or DetailData: null
}
Looking at https://api.kloh.in/kloh/external/v1/activity/AID180917200010526C8LFJ4MEIE9CWGXZG4, sometimes the location
field there is null so you'll need to check for that.
For avoiding this scenario I would suggest you to use
https://lodash./docs/4.17.10#get
it is a much cleaner way to get the value for deeply nested property. Install lodash and import it then use
import React from 'react'
import Caro from './Carousel'
import {
Container,
Row,
Col
} from 'reactstrap';
import _ from 'lodash';
class Detail extends React.Component {
constructor(props)
{
super(props)
this.state = {
DetailData: []
}
}
ponentDidMount() {
fetch('https://api.kloh.in/kloh/external/v1/activity/AID180917200010526C8LFJ4MEIE9CWGXZG4', {
method: 'GET'
})
.then((response) => response.json())
.then((data) => {
this.setState({
DetailData: data.response
})
console.log(typeof(this.state.DetailData));
})
}
render() {
return (
<div>
<Caro / >
<Container >
<Row >
<Col xs = "12" sm = {{size: 8, offset: 2 } md = {{size: 8, offset: 2}} >
< div >
<h1> {_.get(this.state, 'DetailData.title', 'any_default_value_for_title')} <h1>
<h1> {_.get(this.state, 'DetailData.location.address', 'any_default_value_for_address')} </h1> {/*getting error here*/}
<hr/>
<h6> {_.get(this.state, 'DetailData.description', 'any_default_value_for_description')} </h6>
</div>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Detail;
This is adding one more library to your project. But this is the clean way to do it.
Your render method is running before de ComponentDidMount function so the initial state is being used there, where the this.state.DetailedData
is an empty array so this.state.DetailData.location
is undefined and you can not check the this.state.DetailData.location.address
without getting an error so you need to check whether it exists the location or not
using react,react-redux, useSelector
useSelector is the hooks alternative to mapstatetoprops
i found that i could not map nested object 'typeerror cannot read property of undefined'
my data looks like this
orderDetails:{loading:_, error:_, order:{etc:_,items:[...,{etc:_}]}
error
useEffect(()=>{...dispatch()},[])
const orderDetails = useSelector(state=>state.orderDetails)
const {order, loading, error}= orderDetails;
worked by using useSelector and selecting deeper state vs destructuring
const order = useSelector(state=>state.orderDetails.order)