Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I reduce this async action/reducer boilerplate pattern? #1661

Closed
abrkn opened this issue Apr 25, 2016 · 7 comments
Closed

How can I reduce this async action/reducer boilerplate pattern? #1661

abrkn opened this issue Apr 25, 2016 · 7 comments
Labels

Comments

@abrkn
Copy link

abrkn commented Apr 25, 2016

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.

@markerikson
Copy link
Contributor

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.

@artivilla
Copy link

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

@abrkn
Copy link
Author

abrkn commented Apr 26, 2016

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

@gaearon
Copy link
Contributor

gaearon commented Apr 28, 2016

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

@FredericHeem
Copy link

@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

@neove
Copy link

neove commented Jul 7, 2016

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

@markerikson
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants