Reputation: 5135
When reading the documentation of Redux library, I have a question about combineReducers
.
When we have a single reducer, it handles all kinds of action types.
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
case 'FOO'
return state + 100
case 'BAR'
return state - 100
case 'SHOW_ME_THE_MONEY'
return state + 10000000000
default:
return state
}
}
Well, you have a code reviewer who said it's not good to have one god reducer to handle all actions. Please create different reducers to do different things.
.
export default function cheat(state = [], action) {
switch (action.type) {
case 'FOO'
return state + 100
case 'BAR'
return state - 100
case 'SHOW_ME_THE_MONEY'
return state + 10000000000
}
}
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
import { combineReducers } from 'redux'
import todos from './cheat'
import counter from './counter'
export default combineReducers({
cheat,
counter
})
store.dispatch({
type: 'SHOW_ME_THE_MONEY',
text: 'To Buy new Macbook Pro 16'
})
When an action FOO
arrives, how does the state know which child reducer should be picked and used for calculating the new state?
I suppose a mapping between action type and reducer is essential, but it seems unnecessary, which is demoed in the documentation.
Upvotes: 1
Views: 263
Reputation: 5135
this official redux FAQ is provided by @louisbl as a comment, but I think it's very helpful, deserved to be exposed as an answer.
Redux FAQ: Actions
A given action could be handled by all, some, or none of them. This keeps components decoupled from the actual data changes, as one action may affect different parts of the state tree, and there is no need for the component to be aware of this. Some users do choose to bind them more tightly together, such as the “ducks” file structure, but there is definitely no one-to-one mapping by default, and you should break out of such a paradigm any time you feel you want to handle an action in many reducers.
Another relating question is:
Redux can I use one action type in separate reducers?
Upvotes: 0
Reputation: 366
combineReducers
is only doing a mapping between your child reducer key (cheat
, counter
) and the corresponding slice of the state (state.cheat
, state.counter
).
The redux basic tutorial walks you through this concept called reducer composition.
Child reducers receive all actions but only their slice of the state:
let {
createStore,
combineReducers
} = Redux
function cheat(state = 0, action) {
console.log("cheat reducer receive action: ", action.type)
console.log("cheat reducer slice: ", state)
switch (action.type) {
case 'FOO':
return state + 100
case 'BAR':
return state - 100
case 'SHOW_ME_THE_MONEY':
return state + 10000000000
default:
return state
}
}
function counter(state = 0, action) {
console.log("counter reducer receive action: ", action.type)
console.log("counter reducer slice: ", state)
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
let combined = combineReducers({
cheat,
counter
})
let store = createStore(combined)
store.subscribe(() => console.log("store state: ", store.getState()))
store.dispatch({
type: 'INCREMENT'
})
store.dispatch({
type: 'INCREMENT'
})
store.dispatch({
type: 'FOO'
})
store.dispatch({
type: 'BAR'
})
store.dispatch({
type: 'SHOW_ME_THE_MONEY'
})
<script src="https://unpkg.com/redux/dist/redux.js"></script>
Upvotes: 2