dipole_moment dipole_moment - 25 days ago 9
React JSX Question

Updating isLoading field on a redux store

I have spinner that indicates my app is loading. Many reducers in my app need to be able to set this loader to either true or false.

My Assumption:
This field needs to live on the top most level of the state tree. Let's call it

isLoading
.

The Problem:
Redux reducers update their own portion of the state tree. What are some ways I can structure my reducers to update the
isLoading
field on the top most level?

I am familiar with
redux-thunk
but it seems like a bit of an overkill to dispatch an event on every action. But maybe I'm wrong and that is the correct approach. Also, it is certainly possible I am designing my state tree incorrectly.

For reference, I am currently using redux thunk as such:

export const fetchAssets = () => {
return dispatch => {
request
.get('http://myapi.com/assets')
.set('Accept', 'application/json')
.end(function(err, res){
if (err) {
return dispatch(fetchAssetsFailure(err));
}
dispatch(fetchAssetsSuccess(res.body.data));
});
}
}

Answer

Reducers receive all dispatched actions, so you want your isLoading reducer to react to every relevant action, instead of other reducers setting this value. Obviously, you can't use the action.type since you can't predict all relevant actions, and it will create a very cumbersome reducer. What you can do is add another field to the action, and this reducer will react to that field.

Sample action creator:

const createSampleAction = (payload, isLoading) => ({
    type: 'SAMPLE_ACTION',
    payload,
    meta: {
        isLoading
    }
});

And the reducer:

const isLoadingReducer = (state = false, { meta }) => {
  const isLoading = meta && meta.isLoading;

  if (isLoading !== undefined) {
      return isLoading;
  }

  return state;
}

If you're not comfortable with reducers that use the meta instead of the action type, you can create a middleware that will do the same property to dispatch showLoading / hideLoading actions, and the reducer will react to those actions:

const isLoadingMiddleware = ({ dispatch }) => next => {
  next(action);
  const isLoading = action.meta && action.meta.isLoading;

  if (isLoading !== undefined) {
      dispatch(isLoading ? showLoading () : hideLoading());
  }
}