Redux Easy Async
Redux Easy Async makes handling asynchronous actions, such as API requests,
simple, reliable, and powerful.

Table of Contents
Overview
Redux is fantastic tool for managing application state but since actions, by their
very nature, are synchronous, asynchronous requests (such as to APIs) can be
more challenging. Standard approaches involve a lot of boilerplate, reinventing
the wheel, and opportunity for error. For more info see: Motivation
Redux Easy Async provides a simple yet powerful approach for creating and
tracking asynchronous actions. Features:
- Create asynchronous actions (including associated constants for start,
success, and fail) with a single call.
- Create reducer(s) that automatically track the status of asynchronous actions,
i.e. pending, completed. No more dispatching loading actions or storing
isFetching
state.
- Optional configuration to parse API responses pre-reducer, conditionally
make requests, prevent multiple requests, and more.
- Makes all your dreams come true and turns you into the person you always
wanted to be.
Installation
With NPM:
npm install redux-easy-async --save
or with Yarn:
yarn add redux-easy-async
Basic Usage
-
Add the async middleware to wherever you create your redux store:
import { createStore, applyMiddleware } from 'redux';
import { createAsyncMiddleware } from 'redux-easy-async';
const asyncMiddleware = createAsyncMiddleware();
createStore(rootReducer, applyMiddleware(asyncMiddleware));
-
Create an async action:
import { createAsyncAction } from 'redux-easy-async';
export const fetchUser = createAsyncAction('FETCH_USER', (id) => {
return {
makeRequest: () => fetch(`https://myapi.com/api/user/${id}`),
};
});
-
Handle the action in a reducer somewhere:
const usersReducer = (state = {}, action) => {
const { type, payload } = action;
switch (type) {
case fetchUser.SUCCESS_TYPE:
case fetchUser.FAIL_TYPE:
default:
return state;
}
};
-
Dispatch the action somewhere in your app:
dispatch(fetchUser(1));
-
Profit!
Advanced Usage
Automatially track request status, show a loading spinner
-
add a requests reducer that will track all async actions:
import { createAsyncReducer } from 'redux-easy-async';
const requestsReducer = createAsyncReducer([fetchPost]);
-
Add the requests reducer to your main reducer somewhere:
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
requests: requestsReducer,
});
-
Show loading spinner in a component somewhere:
const isLoading = requests.FETCH_USER.hasPendingRequests;
return (
<div>
{ isLoading && <div>Show a loading spinner</div> }
{ !isLoading && <div>Show user data</div> }
</div>);
Working examples
The examples directory includes fully working examples which you can run locally and test out Redux Easy Async.
-
Install dependencies for the example you want to try (with npm or yarn):
> cd examples/basic
> npm install (or yarn install)
-
Start the server
> npm start (or yarn start)
-
Go to http://localhost:4001/
in your browser.
Motivation
API
createAsyncAction(type, fn, [options]) ⇒ function
Kind: global function
Returns: function
- actionCreator
type | string | object | | can either be a string (e.g. "GET_POSTS") or a a constants object created with createAsyncConstants. |
fn | function | | action creator function that returns an object with action configuration. See example below for configuration options. Only makeRequest is required . |
[options] | Object | | additional configuration options |
[options.namespace] | Object | REDUX_EASY_ASYNC_NAMESPACE | the middleware action type this action will be dispatched with. You most likely don't want to modify this unless for some reason you want multiple instances of async middleware. |
Example (All configuration options for async action)
import { createAsyncAction } from 'redux-easy-async';
const myAction = createAsyncAction('MY_ACTION', () => {
return {
makeRequest: () => fetch('/api/posts'),
meta = {},
shouldMakeRequest = (state) => true,
parseStart = () => null,
parseSuccess = resp => resp,
parseFail = resp => resp,
}
})
createAsyncConstants(type) ⇒ object
Creates an object with constant keys NAME
, START_TYPE
, SUCCESS_TYPE
, FAIL_TYPE
in the
format that createAsyncAction, createAsyncReducer, and
createAsyncReducer accept. Note: this is an extra optional step for those that
prefer to separate action creator definitions from constants. If you don't know/case then just
createSingleAsyncAction.
Kind: global function
Returns: object
- returns an object with keys: NAME
, START_TYPE
, SUCCESS_TYPE
, and
FAIL_TYPE
type | string | the base name for this constant, e.g. "GET_USER" |
Example
const GET_USER = createAsyncConstants('GET_USER');
createAsyncMiddleware(options) ⇒ function
Creates an instance of middleware necessary to handle dispatched async actions created with
createAsyncAction.
Kind: global function
Returns: function
- redux middleware for handling async actions
options | object | | options to create middleware with. |
[options.requestOptions] | object | {} | options that will be passed to all action's makeRequest functions: e.g. makeRequest(state, requestOptions) . |
[options.namespace] | string | "REDUX_EASY_ASYNC_NAMESPACE" | the action type the middleware will listen for. You most likely don't want to modify this unless for some reason you want multiple instances of async middleware. |
Example
import { createAsyncMiddleware } from 'redux-easy-async';
const asyncMiddleware = createAsyncMiddleware();
...
createAsyncReducer(types) ⇒ function
Creates a requests reducer that automatically tracks the status of one or more async actions
created with createAsyncAction. As you dispatch async actions this reducer will
automatically update with number of requests, request meta for each, a boolean for whether any
requests are currently pending for this request.
Kind: global function
Returns: function
- Redux reducer automatically tracking the async action(s)
types | Array | String | Object | function | one or more async actions to track. Either a single instance or an array of one or more of the following: a string (e.g. `"GET_POSTS"``), a constants object created with createAsyncConstants, or an async action created with createAsyncAction. Typically you will want to pass an array of actions to track all async actions for your application in one place. |
Example
import { createAsyncAction, createAsyncConstants } from '`redux-easy-async';
const FETCH_POSTS = 'FETCH_POSTS';
export const fetchUser = createAsyncAction('FETCH_USER', (id) => {
return {
makeRequest: () => fetch(`https://myapi.com/api/user/${id}`),
};
});
const fetchComments = createAsyncConstants('FETCH_COMMENTS');
const requestsReducer = createAsyncReducer([FETCH_POSTS, fetchUser, fetchComments]);
Meta
Author: Evan Hobbs - NerdWallet
License: MIT - LICENSE
for more information.
Todo
- images/logo
- finish Motivation section.
- add error logging in middleware?
- add more complicated example