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.
Well, no matter what you pass to dispatch , it is still a single action. Even if your action is an array of objects, or a function which can then create more action objects!
Reducers: As we already know, actions only tell what to do, but they don't tell how to do, so reducers are the pure functions that take the current state and action and return the new state and tell the store how to do.
It turns out that Redux lets us combine multiple reducers into one that can be passed into createStore by using a helper function named combineReducers . The way we combine reducers is simple, we create one file per reducer in the reducers directory.
When you dispatch an action creator it passes the action object to the root reducer. The action object is passed through the entire state tree and any reducers that process the action type consume it.
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: Redux: Why not put actions and reducer in same file?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With