Neuron Powered Motorization

    use-reducer-async
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.1 • Public • Published

    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.

    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 }) => 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>
      );
    };

    Notes for abortability

    If an async action handler dispatches an action after the component is unmounted, React in the development mode warns about possible memory leaks.

    It is the responsibility of the async action handler to deal with such cases.

    All async action handlers receive signal in the argument. Refer examples/04_abort/src for the usage.

    Note: The implementation depends on AbortController in the DOM spec. If you are using an environment that doesn't have AbortController (for example IE11), you need a polyfill: 1 2

    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, signal }) => async (action) => {
        dispatch({ type: 'START_SLEEP' });
        await new Promise(r => setTimeout(r, action.ms));
        dispatch({ type: 'END_SLEEP' });
      },
      FETCH: ({ dispatch, getState, signal }) => 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 04

    Install

    npm i use-reducer-async

    DownloadsWeekly Downloads

    1,799

    Version

    2.0.1

    License

    MIT

    Unpacked Size

    32.6 kB

    Total Files

    12

    Last publish

    Collaborators

    • daishi