Redux can I use one action type in separate reducers?

ReduxReact Redux

Redux Problem Overview


I have a situation in my Redux application where I currently have 3 separate reducers that handle the fetching of data from an api. An example of one of my reducers would be:

const INITIAL_STATE = {
  data: [],
  loading: false,
  error: ''
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_ALL_ORDERS_START:
      return {
        ...state,
        loading: true
      };
    case GET_ALL_ORDERS_SUCCESS:
      return {
        ...state,
        allOrders: action.payload,
        loading: false
      };
    case GET_ALL_ORDERS_FAIL:
      return {
        ...state,
        loading: false,
        error: action.payload
      };
    default:
      return state;
  }
};

Note the loading and error states, these are identical in each current reducer and will be for any subsequent reducers I write that involve fetching data from the api.

I would like to add a further reducer that is used only for the loading and error pieces of state. The other 3 would store the data.

This would give me:

Data reducers x 3

const INITIAL_STATE = {
  data: []
  // any other state in the future
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_ALL_ORDERS_SUCCESS:
      return {
        ...state,
        allOrders: action.payload
      };
    default:
      return state;
  }
};

Loading / Error reducer (handles loading / error for entire app)

const INITIAL_STATE = {
  loading: false,
  error: ''
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_ALL_ORDERS_START:
      return {
        ...state,
        loading: true
      };
    case GET_ALL_ORDERS_SUCCESS:
      return {
        ...state,
        loading: false
      };
    case GET_ALL_ORDERS_FAIL:
      return {
        ...state,
        loading: false,
        error: action.payload
      };
    default:
      return state;
  }
};

As you can see this means the GET_ALL_ORDER_SUCCESS action type will be used in 2 separate reducers. My question is, is this ok? or does it go against convention?

Many thanks in advance.

Redux Solutions


Solution 1 - Redux

I think that's perfectly fine. There is no place to states that Actions and Reducers have a 1:1 mapping. In fact, creator of Redux explicitly says that there is no relation between them, many reducers can react to a single actions, a single reducer can react to multiple actions.

I think he says it best: https://github.com/reduxible/reduxible/issues/8

Tweet: https://twitter.com/dan_abramov/status/691608868628119552

Relevant SO: https://stackoverflow.com/questions/37111300/redux-why-not-put-actions-and-reducer-in-same-file

Solution 2 - Redux

I had a similar question if I could use the same action type name in two or more separate reducers and the answer is definitely no if there is not a very exceptional case.

Why not?

Even we write reducers separately after combining them by combineReducers function when we dispatch the action all reducers are called their switch case statements.

Reducer one:

export const postReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case "SET_DATA":
      const { posts } = action.payload;
      return {
        ...state,
        posts: posts,
      };
  }
};

Reducer two:

export const commentReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case "SET_DATA":
      const { comments } = action.payload;
      return {
        ...state,
        comments: comments,
      };
  }
};

So when we dispatch an action with type SET_DATA both reducer will be called and if payload value is

{
  comments: ['comment one', 'comment two'] 
}

post reducer will set its posts to undefined.

A better solution would be to name types like this:

case "SET_POST_DATA":

case "SET_COMMENT_DATA": 

to avoid collision between two reducer's actions.

The convention is that when action is called there is only one reducer who is responsible to answer that action otherwise it can cause misunderstanding for other developers

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmtwalletView Question on Stackoverflow
Solution 1 - ReduxjulianljkView Answer on Stackoverflow
Solution 2 - ReduxTornike MenabdeView Answer on Stackoverflow