AJAX Requests in React: How and Where to Fetch Data

By Dave Ceddia

One of the first questions new React developers have is, “How do I do AJAX requests in React?” a.k.a. “How do I make API calls in React?”

Here’s an answer to that question.

First: React itself doesn’t have any allegiance to any particular way of fetching data. In fact, as far as React is concerned, it doesn’t even know there’s a “server” in the picture at all.

React simply renders components, using data from only two places: props and state.

So therefore, to use some data from the server, you need to get that data into your components’ props or state.

You can complicate this process with services and data models (er, “build abstractions”) as much as you desire, but ultimately it’s just components rendering props and state.

Choose an HTTP Library

To fetch that data from the server, you’ll need an HTTP library. There are a ton of them out there. Ultimately they all do the same thing, but they have different features.

Like promises? Go with axios.

Hate promises, but love callbacks? Take a look at superagent.

Rather use something soon-to-be-standardized? fetch might be your favorite.

The thing is, it doesn’t really matter. There’s no “best.”

Some will say that fetch is the best because it’s part of the standard, but despite that, there are still competing HTTP libraries that many people continue to use and prefer. So use what you like.

I like axios and I think React and Axios pair nicely together, so that’s what I’ll show here. But seriously, if you don’t like it for some reason, go look at one of the other options.

Fetch The Data With Axios and React

Here’s a simple example component that fetches the posts from a subreddit (/r/reactjs in this case). Take a look at it, and we’ll go over how it works.

import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';

class FetchDemo extends React.Component {
  state = {
    posts: []
  }

  componentDidMount() {
    axios.get(`http://www.reddit.com/r/${this.props.subreddit}.json`)
      .then(res => {
        const posts = res.data.data.children.map(obj => obj.data);
        this.setState({ posts });
      });
  }

  render() {
    return (
      <div>
        <h1>{`/r/${this.props.subreddit}`}</h1>
        <ul>
          {this.state.posts.map(post =>
            <li key={post.id}>{post.title}</li>
          )}
        </ul>
      </div>
    );
  }
}

ReactDOM.render(
  <FetchDemo subreddit="reactjs"/>,
  document.getElementById('root')
);

How It Works

First, we import the axios library:

import axios from 'axios';

We’re initializing state at the top using a class property. You can also write this using a constructor, and they’re functionally equivalent. I like the class property because it’s just less code to write.

componentDidMount is where the magic happens. This method will be executed when the component “mounts” (is added to the DOM) for the first time. This method is only executed once during the component’s life.

TL;DR: Fetch server data in the componentDidMount lifecycle method

It uses the axios.get function to fetch the data from the subreddit, based on the subreddit prop passed in during render at the bottom. The backticks are an ES6 template string, and it probably does what you think: the ${...} part is replaced by the value of that expression, so the URL passed to axios.get is actually http://www.reddit.com/r/reactjs.json.

Two things to note here, specific to Reddit:

  • You can tack on .json to the end of any subreddit URL and get a JSON representation of the posts there.

  • If you forget the www you’ll get a CORS error (at least, I did).

Since Axios uses promises, we chain the call with .then to handle the response. The posts are extracted after a little bit of transformation, and then the important bit:

The component’s state is updated by calling this.setState with the new array of posts. This triggers a re-render, and then the posts are visible.

That’s all there is to it!

Bonus: Loading Indicator

Can you think of how to modify the code to add a “Loading…” message while the request is in flight?

Hint: set a flag in state that will toggle once the request completes. Use that flag in the render function to show the loading indicator.

Download the Example Code

I put together the example code with the bonus Loading Indicator and included unit tests too. You can download it right here, no email required or anything:

Unzip it, run npm install, then npm start.

Translations