TEMP
TEMP

Reputation: 235

ReactJS: get data from api and map data

I am learning ReactJS. In my program, I am making an API call and later mapping it. The data which is fetched by API call is like, data = [{"uid":"1", "title":"hello"},{"uid":"2", "title":"World"}]

import ImporterAPI from '../api';
const API = new ImporterAPI();

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: ''
  }}

  componentWillMount() {
    this.setState({ data: API.getData()}, () => {
      console.log("data fetched");
      var mapData = []
      this.state.data.map( (object, i) => {
        mapData.push(<p key={i}>{object}</p>)
      })
  }) 
  }

  render() {
    return (
      <div className="home">
        {this.mapData}
      </div>
    )
  }
}

And my API file,

import axios from 'axios';
class API {
  getData = () => {
    axios.get('http://localhost:8005/data')
    .then(function (response) {
      if (response.status === 200 && response != null) {
        var data = response.data;
        console.log(data)
        return data
      } else {
        console.log('problem');
      }
    })
    .catch(function (error) {
      console.log(error);
    });
  }
}

My console.log is printing the data from API call and then I'm returning the data. Where in home component data is assigned using setState. But there is no data storing into this.state.data. It always remains undefined and I got error "TypeError: Cannot read property 'map' of undefined".

Please guide me. How should I print API call data & I would also like to know if this program is good or bad in terms of performance for making API calls or any other better way to improve performance. Thanks.

I would appreciate help.

Upvotes: 4

Views: 30346

Answers (2)

Hemadri Dasari
Hemadri Dasari

Reputation: 33994

Do you really need another class for getting api data? Not required

Also componentWillMount method is deprecated so I would recommend you to move your axios code to componentDidMount method within the class.

Also initialize the data with empty array instead of string. And set the api response data to state i.e., data

Do map directly in render and display data.

Use arrow function in axios .then and .catch like I did in the below code otherwise this won’t be available to access state or props. You need to bind every .then and .catch otherwise

Your code can be simplified something like below

     class Home extends Component {
         constructor(props) {
            super(props);
            this.state = {
               data: []
            }
         }

      componentDidMount() {
          axios.get('http://localhost:8005/data')
            .then(response => {
                if (response.status === 200 && response != null) {
                  this.setState({
                       data: response.data
                  });
           } else {
             console.log('problem');
           }
      })
      .catch(error => {
          console.log(error);
      });
    }

    render() {
       const { data } = this.state;
       return (
          <div className="home">
            {Array.isArray(data) && data.map(object => (
                 <p key={object.uid}>{object.title}</p>
             ))}
          </div>
        )
    }
  }

Upvotes: 3

Mir
Mir

Reputation: 114

There're two problems in your code.

First, API.getData() is an async function. It means when you call API.getData(), the data is not return intermediately (think like it takes few milliseconds to get the data). You should setState after you fetched the data.

Secondly, you should send render logic in render function.

It should look like this:

import React, { Component } from 'react'
import ImporterAPI from '../api'
const API = new ImporterAPI()

class Home extends Component {
  constructor(props) {
    super(props)
    this.state = {
      data: []
    }
  }

  componentWillMount() {
    API.getData().then(response => {
      console.log('Data fetched', response)
      this.setState({
        data: response
      })
    })
  }

  render() {
    return (
      <div className="home">
        {this.state.data.map((object, index) => (
          <p key={index}>{object}</p>
        ))}
      </div>
    )
  }
}

As @Askiron answer, you also should return axios.... in your API function.

Edit 2: Here's the better API, which return data in error case, so you don't get this.state.data is not a function:

import axios from 'axios'

class API {
  getData = () => {
    return axios
      .get('http://localhost:8005/data')
      .then(function(response) {
        if (response.status === 200 && response != null) {
          var data = response.data
          return data
        } else {
          throw new Error('Empty data')
        }
      })
      .catch(function(error) {
        console.log(error)
        return [] // Return empty array in case error response.
      })
  }
}

Upvotes: 2

Related Questions