user3794648
user3794648

Reputation: 483

Fetching data from JSON and displaying it

I'm trying to fetch the contents of a static JSON file and display it in react.js. I'm basing my code on the examples given Here The code compiles, but when I open the page in a browser, I get this error message:

TypeError: Cannot read property 'data' of null

Here's my component:

import React, { Component } from 'react';

class UserList extends Component {

    async getData(){
       const res = await fetch('/static/users.json');
       const data = await res.json();
       console.log("Got Data : " + data.length);
       return this.setState(
            {data:data}
       );
    }

    componentDidMount()
    {
       this.getData();
    }

    render(){
        return (
          <ul>{this.state.data.map(item => <li>{item.title}</li>)} </ul>
        )
    }
}

export default UserList;

Upvotes: 0

Views: 177

Answers (3)

carlosrberto
carlosrberto

Reputation: 893

Your initial state declaration is missign:

import React, { Component } from 'react';

class UserList extends Component {
  state = {
    data: []
  };
  
  // ...
}

export default UserList;

Upvotes: 0

Will T
Will T

Reputation: 655

Its because setState internals update asynchronously and may not be set by the time your code tries to read data.

You could do:

 render(){
    return (
      <ul>{this.state.data && this.state.data.map(item => <li>{item.title}</li>)} </ul>
    )
}

This will only try and map over your array if this.state.data is not equal to null.

*** EDITED ****

You have also not constructed your state which is why the null check isn't working.

import React, { Component } from 'react';

class UserList extends Component {
constructor(props) {
  super(props);
  // Don't call this.setState() here!
   this.state = { 
      data: null,
   };
 }

async getData(){
   const res = await fetch('/static/users.json');
   const data = await res.json();
   console.log("Got Data : " + data.length);
   this.setState({data});
}

componentDidMount()
{
   this.getData();
}

render(){
    return (
      <ul>{this.state.data.map(item => <li>{item.title}</li>)} </ul>
    )
}
}

export default UserList;

Upvotes: 0

Levi
Levi

Reputation: 116

getData is an asynchronous function, as well as setState. This creates a race condition between the time your component mounts, to the time it renders. Therefore you need to null check.

import React, { Component } from 'react';

class UserList extends Component {

    async getData(){
       const res = await fetch('/static/users.json');
       const data = res.json();
       console.log("Got Data : " + data.length);
       return this.setState(
            {data:data}
       );
    }

    componentDidMount()
    {
       this.getData();
    }

    render(){
        return (
          <ul>{this.state && this.state.data && this.state.data.map(item => <li>{item.title}</li>)} </ul>
        )
    }
}

export default UserList;

Upvotes: 2

Related Questions