React AJAX Best Practices

February 5th, 2016

When you start asking about AJAX and React, the first thing the experts will tell you is that React is a view library and React has no networking/AJAX features.

It's good to know, but not very helpful when you just want to get data from the server into your React components.

The truth is, there are a ton of ways to do it. You probably have thought of a couple ways yourself, but if you choose the wrong way, your code could get messy.

So you're left wondering: what is the 'right' or 'preferred' way?

What is the best practice for getting server data into React components?

And the answer is.... it depends.

Four Ways

I've collected four good ways to use AJAX with React.

Which approach you use depends on the size and complexity of your app, along with which libraries or technologies you are already using.

These are your options:

1. Root Component

This is the simplest approach so it's great for prototypes and small apps.

With this approach, you build a single root/parent component that issues all your AJAX requests. The root component stores the AJAX response data in it's state, and passes that state (or a portion of it) down to child components as props.

root

For an example of this approach take a look at the official React tutorial. The CommentBox component is the root component that sends all the AJAX requests.

The thing I don't like about the official tutorial: they are using jQuery to send AJAX requests. jQuery is a large library with many features, so using it just for AJAX doesn't make sense.

I recommend using fetch(). It is a simple, standardized, JavaScript AJAX API. It is already supported by Chrome and Firefox, and polyfills are available for node and other browsers. For details, or for help choosing your own AJAX library, see my AJAX library comparison.

Another caveat: if you have a deep component tree (subcomponents of subcomponents of subcomponents...) then you will have to pass data a long way from the root component to your deeper components.

When to use a root component:

  • You have a shallow component tree.
  • You're not using Redux or flux.

2. Container Components

A container component "provides the data and behavior to presentational or other container components." If you haven't heard the term yet, I suggest Dan Abramov's article on presentational and container components.

diagram

For our purposes, the container component approach is just like the root component approach, except with multiple components that can interact with the server.

Here's how it works: for every presentational component that needs data from the server, create a container component that sends AJAX requests to get that data, and provides it to the child component via props.

As a concrete example, imagine you want to display a user profile with a name and a picture.

First build a <UserProfile /> presentational component that accepts a name and a profileImage prop. This component should not have any AJAX code.

Then build a <UserProfileContainer /> component that accepts a userId. It downloads the data for that particular user, and passes it to <UserProfile /> via props.

The AJAX requests in the container components can be sent with a simple AJAX library. I recommend fetch().

When to use container components for AJAX:

  • You have a deep component tree.
  • Many of your components do not require data from the server, but some do.
  • You are fetching data from multiple APIs or endpoints.
  • You're not using Redux/flux, or you prefer container components to 'async actions'.

3. Redux Async Actions

redux async actions

Redux manages data, and AJAX provides data from the server, so it makes sense that your Redux code should be handling your network requests.

If you are using Redux, don't put AJAX in your React components. Instead, put it in your Async Actions.

I recommend using fetch() to make the actual network requests, and luckily, that's also what Redux uses in their official documentation. They've even written an example reddit API that uses Redux, React, and fetch().

If you are using another flux, the approach is similar - send network requests in your actions.

When to use a Redux Async Actions:

  • If you're using Redux, this is the way to go.
  • If you're using another flux, there will be a similar approach you can use.

4. Relay

relay

With Relay, you declare the data needs of your React components with GraphQL, and Relay automatically downloads that data and fills out the component props.

Relay works great for large applications, but requires a large up-front time investment. You need to:

  • Learn about Relay and GraphQL.
  • Specify the data needs of your React components with GraphQL (instead of propTypes).
  • Set up a GraphQL server.

Relay is only meant to communicate with GraphQL servers, so it won't help you communicate with any 3rd party APIs.

Currently, Relay can only communicate with a single GraphQL server, so if you are getting data from multiple sources, this approach is not for you. The ability to communicate with multiple servers will likely be added in the future, it is discussed deep in this github issue.

If you're going with this approach, the Relay Playground is a great place to start figuring out how Relay works.

When to use Relay:

  • You're building a large application and are worried about the problems that Relay was designed to solve.
  • You don't have a JSON API built yet.
  • You are willing to set up a GraphQL server.
  • Your app will only communicate with a single server.

Bonus: Anti-patterns

If all of the above ways are correct, then which ways aren't correct? Here are 2 common approaches that I suggest avoiding.

Anti-pattern 1: AJAX requests in presentational components.

Don't add AJAX logic to a component that is already responsible for something else - like complex interface rendering. Doing so would violate the separation of concerns design principle.

Anti-pattern 2: ReactDOM.render()

You could have AJAX logic living outside of React entirely and call ReactDOM.render() whenever you receive an update from the server.

This approach might work okay. I list it as an antipattern because I believe the root component approach is similar, but cleaner.

Conclusion

Applications built with React are modular. React is just one of the modules. The AJAX library is another. This isn't Rails or Angular.

You might sometimes need help figuring out what the other modules are and how they fit together.

What's the best library for X? and How do I use React with Y? - These are the kinds of questions you'll see answered on this blog - with regular new posts.