For any meaningful application, putting all your update logic into a single reducer function is quickly going to become unmaintainable. While there's no single rule for how long a function should be, it's generally agreed that functions should be relatively short and ideally only do one specific thing. Because of this, it's good programming practice to take pieces of code that are very long or do many different things, and break them into smaller pieces that are easier to understand.
Since a Redux reducer is just a function, the same concept applies. You can split some of your reducer logic out into another function, and call that new function from the parent function.
These new functions would typically fall into one of three categories:
(state, action)parameter signature
For clarity, these terms will be used to distinguish between different types of functions and different use cases:
(state, action) -> newState(ie, any function that could be used as an argument to
createStore. This is the only part of the reducer logic that must have the
(state, action) -> newStatesignature.
The term "sub-reducer" has also been used in various discussions to mean any function that is not the root reducer, although the term is not very precise. Some people may also refer to some functions as "business logic" (functions that relate to application-specific behavior) or "utility functions" (generic functions that are not application-specific).
Breaking down a complex process into smaller, more understandable parts is usually described with the term functional decomposition. This term and concept can be applied generically to any code. However, in Redux it is very common to structure reducer logic using approach #3, where update logic is delegated to other functions based on slice of state. Redux refers to this concept as reducer composition, and it is by far the most widely-used approach to structuring reducer logic. In fact, it's so common that Redux includes a utility function called
combineReducers(), which specifically abstracts the process of delegating work to other reducer functions based on slices of state. However, it's important to note that it is not the only pattern that can be used. In fact, it's entirely possible to use all three approaches for splitting up logic into functions, and usually a good idea as well. The Refactoring Reducers section shows some examples of this in action.