Skip to content
React useReducer with async actions
TypeScript JavaScript
Branch: master
Clone or download
Latest commit e662dd4 Jan 18, 2020
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
__tests__ fix eslint config Dec 22, 2019
dist run compile Jan 17, 2020
examples rename to ExportAction and make it omittable Jan 17, 2020
src rename to ExportAction and make it omittable Jan 17, 2020
.eslintrc.json fix eslint config Jan 17, 2020
.gitignore initial commit Oct 22, 2019
.travis.yml initial commit Oct 22, 2019
CHANGELOG.md v0.6.0 Jan 17, 2020
LICENSE rename to ExportAction and make it omittable Jan 17, 2020
README.md update apidoc Jan 17, 2020
jest.config.js initial commit Oct 22, 2019
package-lock.json v0.6.0 Jan 17, 2020
package.json v0.6.0 Jan 17, 2020
tsconfig.json initial commit Oct 22, 2019
webpack.config.js fix webpack config Jan 9, 2020

README.md

use-reducer-async

Build Status npm version bundle size

React useReducer with async actions

Introduction

React useReducer doesn't support async actions natively. Unlike Redux, there's no middleware interface, but hooks are composable.

This is a tiny library to extend useReducer's dispatch so that dispathing async actions invoke async functions.

Known issues:

  • No abortability (yet)

Install

npm install use-reducer-async

Usage

const initialState = {
  sleeping: false,
};

const reducer = (state, action) => {
  switch (action.type) {
    case 'START_SLEEP': return { ...state, sleeping: true };
    case 'END_SLEEP': return { ...state, sleeping: false };
    default: throw new Error('no such action type');
  }
};

const asyncActionHandlers = {
  SLEEP: (dispatch, getState) => async (action) => {
    dispatch({ type: 'START_SLEEP' });
    await new Promise(r => setTimeout(r, action.ms));
    dispatch({ type: 'END_SLEEP' });
  },
};

const Component = () => {
  const [state, dispatch] = useReducerAsync(reducer, initialState, asyncActionHandlers);
  return (
    <div>
      <span>{state.sleeping ? 'Sleeping' : 'Idle'}</span>
      <button type="button" onClick={() => dispatch({ type: 'SLEEP', ms: 1000 })}>Click</button>
    </div>
  );
};

API

useReducerAsync

useReducer with async actions

Parameters

  • reducer R
  • initialState ReducerState<R>
  • asyncActionHandlers AsyncActionHandlers<R, AsyncAction>

Examples

import { useReducerAsync } from 'use-reducer-async';

const asyncActionHandlers = {
  SLEEP: (dispatch, getState) => async (action) => {
    dispatch({ type: 'START_SLEEP' });
    await new Promise(r => setTimeout(r, action.ms));
    dispatch({ type: 'END_SLEEP' });
  },
  FETCH: (dispatch, getState) => async (action) => {
    dispatch({ type: 'START_FETCH' });
    try {
      const response = await fetch(action.url);
      const data = await response.json();
      dispatch({ type: 'FINISH_FETCH', data });
    } catch (error) {
      dispatch({ type: 'ERROR_FETCH', error });
    }
  },
};
const [state, dispatch] = useReducerAsync(reducer, initialState, asyncActionHandlers);

Returns [ReducerState<R>, Dispatch<ExportAction>]

Examples

The examples folder contains working examples. You can run one of them with

PORT=8080 npm run examples:01_minimal

and open http://localhost:8080 in your web browser.

You can also try them in codesandbox.io: 01 02 03

You can’t perform that action at this time.