1

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: []
    }

  }




  componentDidMount() {

    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;

6
  • Can you do console.log(this.state.DetailData); and share the data 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 ???? Commented Sep 20, 2018 at 13:42
  • The whole DetailData object is displayed Commented Sep 20, 2018 at 13:42
  • @hadi could you add the JSON or console output to the question please? Commented Sep 20, 2018 at 13:45
  • You need to wait for the component 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 componentDidMount method and then conditionally render bases on that isLoaded . Read the link Commented Sep 20, 2018 at 13:51

5 Answers 5

7

When the component 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 component but seem to be expecting an object instead.

this.state = {
  DetailData: [] // this should be DetailData: {} or DetailData: null
}
Sign up to request clarification or add additional context in comments.

5 Comments

If this were the case, other attempts to access the fields (e.g., this.state.DetailData.title) would fail as well.
@PetrBroz I think this is the case. DetailData.title is undefined but doesn't throw an error because DetailData exists. But DetailData.location doesn't yet exist and trying to access a nested property throws an error.
Look at the actual API the user is calling (api.kloh.in/kloh/external/v1/activity/…). One of the location fields there is null. That is the reason.
But I agree that the code would likely cause issues due to the pending fetch result, too.
This might be true, but irrelevant. If the data are not available to the component when it mounts then the DetailData.location.address will always throw an error...
0

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.

Comments

0

For avoiding this scenario I would suggest you to use

https://lodash.com/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: []
}

}




componentDidMount() {

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.

Comments

0

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

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.