0

I'm getting a json from an endpoint which looks like this:

{"section":{"name":"name","subsections":[
 {"name":"one","snippets":[{"title":"title","body":"body"}]},
 {"name":"two","snippets":[{"title":"title","body":"body"}]}]
}}

This is how I get the data:

fetchData() {
  axios.get('/api/data')
  .then(response => {
    this.setState({
      section: response.data.section
    })
  })
  .catch(error => {
    console.log(error);
  });
}

componentDidMount() {
  this.fetchData();
}

But when I call this.state.section.subsections[0] I get the following error:

Uncaught TypeError: Cannot read property '0' of undefined

I know that the subsections is an array, but on getting the elements from it. I get an error. Would anyone know what I might be doing wrong?

Edit:

I want to access the state in the render method. I can access this.state.section.name, I can also print this.state.section.subsections on the console. But whenever I try to access the elements using this.state.section.subsections[0] I get an error.

dhaliman
  • 1,542
  • 1
  • 12
  • 23
  • You are fetching the data in `componentDidMount` and accessing it where? Because `componentDidMount` is the last lifecycle hook that gets executed. Why not try to fetch the data in `componentWillMount` ? – Nandu Kalidindi Oct 17 '17 at 07:56
  • I’m accessing it in render() method. – dhaliman Oct 17 '17 at 08:30
  • `componentDidMount` gets invoked after `render` method. Try fetching the data in `componentWillMount` and it could work. – Nandu Kalidindi Oct 17 '17 at 08:35
  • @Nandu i tried. Didn’t work. I’ve just edited the question, please have a look. – dhaliman Oct 17 '17 at 08:45
  • First check if the data is coming as expected then add a check for subsections like `if (this.state.section.subsections) { //execute stuff }`. The only possibility I can think of is that the ajax request is not yet fulfilled by the time render method is called. Once the state is set, render will get called again with the complete response. – Nandu Kalidindi Oct 17 '17 at 08:59
  • Since, I'm using `componentDidMount` I feel that the first time it renders, the `section` is not defined. I added a `if else` in my render and changed `componentDidMount` to `componentWillMount`. Now everything works. – dhaliman Oct 17 '17 at 09:27
  • 1
    Glad it worked! – Nandu Kalidindi Oct 17 '17 at 09:37

2 Answers2

2

You might be trying to access data before it's available,

Try this :

this.setState({
    section: response.data.section
},() => {
    console.log('After state set :' ,this.state.section.subsections[0]);
});

If you get the console.log here , the issue is as I explained above , and if not then you need to console.log(this.state.section) and check the output


First Solution :

Provide default empty array from render

render(){
   const subsections = this.state.section.subsections || [];
   return(...)
}

Second Solution :

Provide default empty array from reducer as initial state

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • I can get `this.state.section` printed on the console. Only when I try to access the elements in the render method, I get the error. – dhaliman Oct 17 '17 at 09:16
1

Uncaught TypeError: Cannot read property '0' of undefined occurs when you try to retrieve a property from an undefined variable.

Essentially, the console is trying to tell you that this.state.section.subsections == undefined, therefore you cannot call for undefined[0].

You might want to check whether or not this.state.section.subsections exists before polling it for variables.

ie.

if (this.state.section.subsections) {

  // Exists.
  console.log(this.state.section.subsections)

} else {

  // Undefined.
  console.log(this.state.section.subsections)

}
Arman Charan
  • 5,669
  • 2
  • 22
  • 32