3 Libraries and 3 Ways to Handle AJAX in React Apps

About the Author:

Kellye Whitney
Our staff is always looking for the latest news, technologies and trends in the developer training space.
,

3 Libraries and 3 Ways to Handle AJAX in React Apps

For React beginners coming from a jQuery background, one of the first few questions that come up is how to perform AJAX requests within a React app. The quick answer to this is you can’t, because React is only a view library. It doesn’t come with the functionality to make AJAX or network requests. But the good news is there are libraries which you can use to add this ability to your apps.
In this article we’re going to look at some of the methods which you can use to make AJAX calls within your React app. As some of you might already know, you can actually use React on the server and on mobile apps. That said, we will only be focusing on React on the browser. The article is divided into two sections. In the first section, we’re going to look at some of the libraries which you can use to easily perform AJAX requests and on the second section, we’re going to look at how you can use those libraries inside your React app.

Libraries to Use

Before diving into using libraries for AJAX requests, it’s important to know that there are two ways in which you can make AJAX requests by using what’s available in the browser: XMLHttpRequest and the Fetch API. If you want to keep your React app as lean as possible, you can use either of those two to perform AJAX requests. Just be sure to check Caniuse.com for browser support.
Here are the list of libraries and sample code on how to use them:

axios

Axios is a promise based HTTP client for the browser and Node.js.

npm install axios
var request = require('axios');
axios.get('https://localhost:3000/data.json')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

Superagent

Superagent is small progressive client-side HTTP request library.

npm install superagent
var request = require('superagent');
request
  .get('https://localhost:3000/data.json')
  .end(function(err, res){
    console.log(res);
  });

Request

Request is a simplified HTTP request client.

npm install request
var request = require('request');
request('https://localhost:3000/data.json', function (error, response, body) {
  if (!error && response.statusCode == 200) {
    console.log(response);
  }
})

Fetch

Here is a polyfill for the Fetch API. This allows support for more browsers.

npm install whatwg-fetch
var fetch = require('whatwg-fetch');
fetch('https://localhost:3000/data.json')
  .then(function(response) {
    return response.json();
  }).then(function(json) {
    console.log(json);
  }).catch(function(err) {
    console.log(err);
  });

Using AJAX in your React App

Now let’s take a look at the methods on how we can actually use those libraries inside a React app. We can make AJAX calls in the following places:

  • Root Component
  • Containers
  • Redux Middleware

Root Component

If your app is fairly light and simple, you can make your AJAX calls within the root component and pass in the response to the relevant components through props. For this to work you need to use state in your root component so that you can update the relevant component when a response comes back. Here’s an example:

import React, { Component } from 'react';
import List from './components/List';
import axios from 'axios';
class App extends Component {
  constructor(){
    super();
    this.state = {
      names: []
    };
  }
  render() {
    return (

); } componentWillMount() { var self = this; axios.get(‘https://localhost:3000/data.json’) .then(function (response) { self.setState({ names: response.data.names }); }) .catch(function (error) { console.log(error); }); } } export default App;
Here’s the code for the List component:

import React, { Component } from 'react';
class List extends Component {
  constructor(props){
    super(props);
  }
  render() {
    return
    {this.props.names.map(this.renderItem)}

; } renderItem(name) { return

  • {name}

; } } export default List;

Containers

If you are using Redux or just a plain React app, you can add your AJAX calls inside containers. The main idea for this approach is to create containers for components that needs to fetch their data via AJAX. This way you’re not violating the Single Responsibility Principle that components should be only used for presentation.
If you’re not aware of it yet, there’s this idea of Presentational and Container components in React. Basically, the idea is that presentational components are concerned with how things look. While container components are concerned with how things work. Here’s an example:

import React, { Component } from 'react';
import ListContainer from './containers/ListContainer';
class App extends Component {
  render() {
    return (

); } } export default App;
Below is the code for the ListContainer. The same code is used for the List component which we’ve seen in the last section. This example uses whatwg-fetch instead of axios.

import React, { Component } from 'react';
import List from '../components/List';
import 'whatwg-fetch';
class ListContainer extends Component {
  constructor(props, context) {
    super();
    this.state = {
        names: []
    };
  }
  componentWillMount() {
    var self = this;
    fetch('https://localhost:3000/data.json')
      .then(function(response) {
          if (response.status >= 200 && response.status < 300) {
            return response.text();
          } else {
            var error = new Error(response.statusText)
            error.response = response
            throw error
          }
      })
      .then(function(body) {
        self.setState({
          names: JSON.parse(body).names
        });
      });
  }
  render() {
    return ;
  }
}
export default ListContainer;

Redux Middleware

Lastly, for medium to large-sized Redux apps, you can put your AJAX calls inside middlewares.
First you need to create the middleware (services/data-service.js). This is where you perform the AJAX request when the GET_NAMES action is executed. If the request fails, dispatch another action named GET_NAMES_FAIL and if it succeeds in getting the data, dispatch the GET_NAMES_OK action. Later on we’ll look at the reducer which will handle these actions. For now, just remember that middlewares are reponsible for dispatching atleast two actions: one for failed request and one for successful request.

import request from 'superagent';
const dataService = store => next => action => {
    next(action);
    switch (action.type) {
        case 'GET_NAMES':
            request
                .get('https://localhost:3000/data.json')
                .end((err, res) => {
                    if (err) {
                        return next({
                            type: 'GET_NAMES_FAIL',
                            err
                        });
                    }
                    const names = JSON.parse(res.text).names;
                    next({
                        type: 'GET_NAMES_OK',
                        names
                    });
                });
            break;
        default:
            break;
    }
};
export default dataService;

The status reducer (reducers/status.js) gets called for each of the actions in the app. The idea here is to return only true once there’s already the data, otherwise return false. Or return the current state if any other action is received:

const status = (state = false, action) => {
    switch (action.type) {
        case 'GET_NAMES':
            return true;
        case 'GET_NAMES_OK':
            return false;
        case 'GET_NAMES_FAIL':
            return false;
        default:
            return state;
    }
}
export default status;

The list reducer (reducers/names.js) is the one which receives the payload data once it becomes available. We already know that the GET_NAMES_OK action is fired when that happens, so we check for that here and simply return the actual data.

export default function listReducer (state = [], action) {
    if (action.type === 'GET_NAMES_OK') {
        return action.names;
    }
    return state;
}

Next, we need to combine those reducers so they’re under the same object with status and names as their properties:

import {
    combineReducers
} from 'redux';
import names from './names';
import status from './status';
const nameList = combineReducers({
    status,
    names
});
export default nameList;

Create the ListContainer (containers/ListContainer.js) which will utilize the array of names. This component subscribes for changes in the store, so that by the time the names array becomes available, it can just update its state. The List component which ultimately displays the data is updated via the names props (note: the code is the same as the List component (components/List.js) that we used in the previous section).

import React, { Component } from 'react';
import List from './List';
class ListContainer extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      names: []
    };
  }
  componentWillMount() {
    this.context.store.subscribe(() => {
        let state = this.context.store.getState();
        this.setState({
          names: state.names
        });
    });
  }
  render() {
    return ;
  }
}
ListContainer.contextTypes = { store: React.PropTypes.object };
export default ListContainer;

Use the ListContainer in your main App (App.js) component

import React, { Component } from 'react';
import ListContainer from './components/ListContainer';
class App extends Component {
  render() {
    return (

); } } export default App;
Finally, bring everything together in your root component (index.js) by creating a store that uses the reducers and the middleware that you created earlier. On the last line, dispatch the GET_NAMES action in order to trigger the execution of the GET_NAMES action in the dataService middleware.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducers/index';
import dataService from './services/data-service';
let store = createStore(reducer, {}, compose(applyMiddleware(dataService)));
ReactDOM.render(
  (
  ),
  document.getElementById('root')
);
store.dispatch({type: 'GET_NAMES'});

Other Methods

The methods mentioned above are just a sample of many ways you can use AJAX within your React app. If you want to learn about the other approaches, read on the following links:

Conclusion

That’s it! In this tutorial you learned about the libraries and ways in which you can make AJAX requests inside your React app. You can check out the codes used in this tutorial on this Github repo