Redux: How can I reduce this async action/reducer boilerplate pattern?

Created on 25 Apr 2016  ·  7Comments  ·  Source: reduxjs/redux

I have thousands of lines along the lines of:

const thing = (state = {}, action) => {
  if (action.type === 'FETCH_THING') {
    if (!action.status) {
      return {
        ...state,
        fetchThingStatus: 'pending',
        fetchThingStatusAt: +new Date,
        fetchThingStatusError: null,
      };
    }

    if (action.status === 'success') {
      return {
        ...state,
        fetchThingStatus: action.status,
        fetchThingStatusAt: +new Date,
        fetchThingStatusError: null,
      };
    }

    if (action.status === 'error') {
      return {
        ...state,
        fetchThingStatus: action.status,
        fetchThingStatusAt: +new Date,
        fetchThingStatusError: action.error.stack,
      };
    }
  }

  return state;
};

const fetchThing = () => (dispatch, getState) => {
  const action = {
    type: 'FETCH_THING',
  };

  dispatch(action);

  fetchThing({
    /// ...
  })
    .then(() => {
      dispatch({
        ...action,
        status: 'success',
      });
    })
    .catch(error => {
      dispatch({
        ...action,
        error: error.message,
      });
    });
};

const shouldFetchThing = (state) => {
  const { thing } = state;

  return thing.fetchThingStatus !== 'pending' &&
    (!thing.fetchThingStatusAt || +new Date - thing.fetchThingStatusAt > 10 * 60e3);
};

const thingMiddleware = ({ getState, dispatch }) => {
  setInterval(() => {
    if (shouldFetchThing(getState())) {
      dispatch(fetchThing());
    }
  }, 1e3);

  return next => action => next(action);
};

The above example is the simplest case. In other cases there are updates with more complicated optimistic concurrency.

question

Most helpful comment

As a first observation, you shouldn't be creating new Dates in your reducers, as that makes them non-deterministic.

Beyond that, if you look at my Redux addons catalog, there's many utilities out there that do various things related to async actions - generating them, tracking status, etc. Might be something that fits your use case.

All 7 comments

As a first observation, you shouldn't be creating new Dates in your reducers, as that makes them non-deterministic.

Beyond that, if you look at my Redux addons catalog, there's many utilities out there that do various things related to async actions - generating them, tracking status, etc. Might be something that fits your use case.

@abrkn this looks a lot similar to your use case: https://github.com/spalger/async-redux-actions.

Thanks for suggestions. I'm also looking into yelouafi/redux-saga

I would start by generating reducers.
We have an example of function that generates reducers and then it being used.

@abrkn, the amount of code to write for asynchronous actions/reducers is just insane, so have a look at redux-act-async which provide 2 functions: createActionAsync and createReducerAsync

you can create new date in your action creators and then get it in your reducer

Since this is a usage question and there isn't anything actionable here, I'm going to close the issue. Feel free to discuss further if needed.

Also, note that I'm currently working on a new documentation page about reducers over in #1784 , which may wind up covering a bit of this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

elado picture elado  ·  3Comments

ms88privat picture ms88privat  ·  3Comments

vraa picture vraa  ·  3Comments

caojinli picture caojinli  ·  3Comments

cloudfroster picture cloudfroster  ·  3Comments