I have a complex state where based on certain conditions other reducer functions are called. Is it bad practice to call reducers in other reducers?
I'm making a custom hook that wraps the dispatch calls, because I might want some other logic (backend calls, logging etc) to go along with the dispatch.
I'm torn between doing what I have now or I could take the conditionals out of the reducers, and in the custom hook have conditionals in there.
From my research theres a few things I can do.
export const game = createSlice({
name: 'game',
initialState,
reducers: {
incrementScale: (state) => {
state.currentScale = state.scales.pop()
if (!state.currentScale) {
state.isGameInProgress = false
} else {
game.caseReducers.incrementNote(state)
}
},
incrementNote: (state) => {
state.currentNote = state.notes.shift()
if (!state.currentNote) {
game.caseReducers.incrementScale(state)
}
state.triesLeft = INTIAL_TRIES
}
}
})
The custom hook
export function useGame() {
const handleIncrementNote() {
//put the undefined checks and other logic in here instead?
dispatch(incrementNote)
}
}
I'm inclined to say no, you shouldn't call reducers from other reducers, but in this case I think it may "safe" to do so since you aren't going outside the slice, though I do see a potential edge-case when both scales
and notes
are empty arrays where each case reducer calls the other and creates a loop and never returns.
My suggestion would be to just apply the logic in each reducer case directly and independent of any other reducer to remove the chance of the logic looping between them:
export const game = createSlice({
name: 'game',
initialState,
reducers: {
incrementScale: (state) => {
state.currentScale = state.scales.pop();
if (!state.currentScale) {
state.isGameInProgress = false;
} else {
// game.caseReducers.incrementNote(state)
state.currentNote = state.notes.shift();
state.triesLeft = INTIAL_TRIES;
}
},
incrementNote: (state) => {
state.currentNote = state.notes.shift();
if (!state.currentNote) {
// game.caseReducers.incrementScale(state)
state.currentScale = state.scales.pop();
}
state.triesLeft = INTIAL_TRIES;
},
},
});