Search code examples
javascriptreactjses6-promise

Accessing data from API and outputting in react


I have an API (/js/feed/sms.json) that returns data that looks like this:

[
    {
        id: 1,
        name: "Test feeds 1",
        headline: "Here is a headline",
        feed-url: "/something?q=1"
    },
    {
        id: 2,
        name: "Test feeds 2",
        headline: "Here is another headline",
        feed-url: "/something?q=2"
    },
    {
        id: 3,
        name: "Test feeds 3",
        headline: "Here is a third headline",
        feed-url: "/something?q=3"
    }
]

I have a couple of React components.

The first is a call to an API: fetch-api-data.jsx:

import * as axios from 'axios';

export default class FetchApiData {
  constructor() {
    console.log('FetchAPIData loaded');
  }
  static shareMyStoryData(URL) {
    return axios.get(URL)
    .then(function (response) {
      
    })
    .catch(function (error) {
      console.log(error);
    });
  }
}

The second is a component that parses the data.

import * as React from 'react';
import * as DOM from 'react-dom';
import PropTypes from 'prop-types';
import axios from 'axios';
import './share-my-story.scss';
import FetchApiData from './fetch-api-data';

class ShareMyStory extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      smsData: ''
    }
  }

  componentDidMount() {
    const URL = '/js/feed/sms.json';
    FetchApiData
      .shareMyStoryData(URL)
      .then((response) => {
        this.setState({smsData: response });
      })
      .catch((error) => {
        console.log(error);
      });
  }

  render() {
console.log(this.state.smsData);
    return (
      <div>
        <h1>{this.state.smsData.name}<h1>
        <h2>{this.state.smsData.headline}</h2>
        <h3><a href={this.state.smsData.link}>{this.state.smsData.link}</a></h3>
      </div>
    );
  }
}

ShareMyStory.propTypes = {
  name: PropTypes.string,
  headline: PropTypes.string,
  link: PropTypes.string,
  smsData: PropTypes.array
}

DOM.render(
  <ShareMyStory/>, document.getElementById('share-my-story'));

I'm having 2 problems:

First is that I'm getting undefined in my console.log of the this.state.smsData.

Second, I need to loop thru that object and output the items in the return. I'm coming from Angular, so I'm familiar with their iterative ng-repeat, but I don't see a similar tool in React. Is there a preferred way to do this?


Solution

  • If you really have that empty .then(function(response){}) in your FetchApiData, then that is the problem. Either add { return response } there (useless, but at least then it should work) OR remove that .then.

    For your second question, as pointed out by others: In React you use the .map method of an array to iterate an array:

    { this.state.smsData.map(data => <div>...</div>) }
    

    Some points: if your smsData is (or will be) an array, then it's better to initialise it with either undefined or an empty array. I would advise undefined, so you can make the distinction between A) there is no data yet, and B. The data has been fetched, but there are no records (i.e. smsData.length === 0)

    In your component you can then check whether to render the data, a loading indicator, or some message that there are no records, something like:

    render() {
        const { smsData } = this.state;
        if (!smsData) { return <div>Loading...</div>; }
        if (smsData) {
            if (smsData.length === 0) { return <div>No data</div>; }
            return smsData.map(data => <div>...</div>);
        }
    }