Making Fetch Happen:

Dave Corson-Knowles
Breaking the Bank
Published in
5 min readOct 4, 2018

Switching to Fetch in a React with Redux Application

This tutorial demos switching to Fetch while working with React and
Redux.

Here at Chime we use ReactOnRails and have found a transition to using Fetch to be a big win. I’d been working with Ajax previously. I’ll show you how we did it.

Let’s create an Errors Reducer that propagates helpful error messages from your backend up to your React components. Then errors can be rendered to the user. We can use this to improve our form handling and CRUD operations.

Our example Actions look like this:

And our matching Errors Reducer looks like this:

This errors reducer pattern can be used with Fetch, Ajax, Axios, raw XMLHttpRequest or any number of other data retrieval tools.

We want to use this reducer with Fetch, so we’ll need to install and save the ‘fetch’ npm package. From your command line:

npm install fetch --save

Honestly, any of those tools will work fine, so why Fetch?

  1. Fetch has great MDN documentation.
  2. If you are switching off of jQuery and want a substitute for Ajax, Fetch is a good standard to adopt.
  3. GitHub has open-sourced a nice polyfill for Fetch that supports older browsers.
  4. If you work with modern JavaScript promises all the time, Fetch will feel comfortable and familiar.
  5. If you don’t, then Fetch will make you familiar with modern promise handling!

Get your Linter ready

We will be working with JSON rendered by your backend and transforming it for use in your frontend. This means the variable names received by Fetch may trigger linter warnings since they won’t necessarily be formatted to follow JavaScript’s camelcase convention.

If you are using ESLint (and you really should be), you’ll want to include this line at the top of each of your Redux Action Creator files:

/* eslint-disable no-undef, camelcase */

If your backend is written in Node or is already serving up data that is CamelCased, you won’t need this line. (In our example, we technically don’t need this either since the one word variable,item, looks the same in both CamelCase and snake_case. I doubt you’ll be restricted to one word variables in practice though, so this is going to be helpful as you build more Redux Action Creators.)

Use the Action Creators in a Fetch Promise Chain

We set up our reducer, now let’s use it!

In our demo, we will include a few lines of configuration for ReactOnRails. You can substitute this with the corresponding requirements from any back-end server you are using in your app.

We import ReactOnRails at the top of the file to handle CSRF security in our requests to the server:

import ReactOnRails from ‘react-on-rails’;

Then we import our error action creators that we made above. This assumes they are in the same local folder as our new file:

import { receiveErrors, clearErrors } from ‘./errorActionCreators’;

As a best practice, always prefer constants over strings in Action Creators. This mitigates against silently failing actions in your Reducers. Mistyped strings are ignored by the Reducer, whereas an undefined constant will raise an appropriate error. This is a major win for trouble-shooting.

export const GET_ITEM = 'GET_ITEM';
export const DELETE_ITEM = 'DELETE_ITEM';
export const RECEIVE_ITEMS = 'RECEIVE_ITEMS';

You will use these constants when creating your synchronous actions:

export const getAdminUser = text => ({
type: GET_ITEM,
text,
});
export const deleteAdminUser = text => ({
type: DELETE_ITEM,
text,
});
export const receiveAdmins = payload => ({
type: RECEIVE_ITEMS,
payload,
});

You can use the following two functions to handle all of your promises.

1) If you are familiar with AJAX but not Fetch or general promise handling, this is the biggest change!

export const status = response => {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
};

2) Meanwhile, this one-liner is pretty handy, you will do this a lot:

export const unwrap = response => response.json();

These will be used in all of your Promise Chaining to DRY out your Action Creators. Here’s what it looks like in action:

export const updateItem = (item) => {
const url = `/api/items/${item.id}`;
const body = JSON.stringify({ item });
return (dispatch) => {
fetch(url, {
credentials: ‘same-origin’,
method: ‘PATCH’,
body,
headers,
})
.then(status)
.then(unwrap)
.then(responseJSON => dispatch(receiveItem(responseJSON)))
.catch(unwrap)
.then(responseJSON => dispatch(receiveErrors(responseJSON)));
};
};

Similarly, here’s the action creator for your show route (to get all items):

export const showItems = () => {
const url = '/api/items/';
return (dispatch) => {
fetch(url, {
credentials: 'same-origin',
method: 'GET',
headers
})
.then(status)
.then(unwrap)
.then(responseJSON => dispatch(receiveItems(responseJSON)))
.catch(unwrap)
.then(errors => dispatch(receiveErrors(errors)));
};
};

We’re using a lot of ES6 implicit object de-structuring there. One of the variables you will have to fill out for it to work properly is headers.

If you are using ReactOnRails, you can configure your headers as follows. Otherwise, you will want to set up headers in the expected format for your backend. You can put this in a utilities folder and make it accessible to all of your different Action Creators.

export const headers = {
‘X-Requested-With’: ‘XMLHttpRequest’,
‘X-CSRF-Token’: ReactOnRails.authenticityToken(),
‘Content-Type’: ‘application/json’,
Accept: ‘application/json’,
};

You’ll want to set your Fetch headers properly for security reasons, especially for CSRF protection.

Now we’ve made Fetch happen

Did you find this useful? Need help with something else? Have a better way to do it? Please tell me all about it in the comments.

If making code reusable like this gives you a thrill of satisfaction, check out career opportunities at Chime.

Wednesday, October 3rd @ Chime

--

--

Dave Corson-Knowles
Breaking the Bank

Ruby Rails React Redux. non-’R’ technologies Redacted