Alex Jover Morales
In Resetting Redux State weโve seen a way to reuse reducer logic to reset the state by creating a root reducer. But thatโs not the only way to reuse reducer logic, and higher-order reducers come into the scene to help us with reusability and reducing code duplication.
Higher-order reducers, unlike the root reducer approach, allow us to apply a certain functionality to the reducers that need it. They do so using functional composition, so letโs first learn that concept.
A higher order function is a function that returns another function as its result. For example, if we have a plain function with the following two arguments:
We could re-write it in a higher-order function by separating their arguments in two nested functions:
Notice the call to greet('Hi ')
function, which returns a function that we are calling as ('little kitty')
. The point is, this approach allow functional composition for code reuse.
Why doing that, you say? Imagine you want to use the greet
function to say Hi ${someone} several times in your code. If you do it with a simple plain function as the first example, youโll need to repeat Hi
several times:
While using a higher order function, we have the ability to easily create a sayHi
function:
You can already see two benefits:
sayHi
function based on a more generic one'Hi '
Of course, this is a simplistic example thatโs merely for education purposes, but that greet
function could be something which performs heavier logic, where the mentioned benefits will be much more obvious.
Now you understand the mechanics of a higher-order function, you might be wondering: howโs that related to reducers? Well, if you think about it, a reducer is simply a function, so when we apply this pattern to reducers we call them higher-order reducers.
Letโs go over an example. Imagine that you have a users and articles reducers, which have a data
property that comes from an API. Something like:
Say that both of the users and articles need to have pagination. Then weโll need to have some actions like GO_NEXT_PAGE
, GO_PREV_PAGE
, UPDATE_TOTAL_PAGES
, etc. It becomes really cumbersome when you need to duplicate all that logic in each of your reducers that need pagination.
Hereโs where we can create a higher-order reducer that, given a reducer, returns a decorated reducer with the additional functionality. Letโs call it withPagination
:
Isnโt this familiar? Yes, the nested function is a reducer. Remember that a reducer has the (state, action)
signature.
Whatโs happening here is that, based on a reducer
given as an argument, weโre returning a new reducer function that adds the GO_NEXT_PAGE
logic, and on the default
statement of the switch, we simply are proxying the call to the original reducer. So with this, weโre adding some functionality only when needed.
We can apply the already created withPagination
higher-order reducer to the reducers weโd like, for example when calling the combineReducers
function to create the appโs root reducer:
Notice that weโre applying the pagination logic only to the users
and articles
reducers. Thatโs the power of higher order reducers: we can apply them as needed.
We still have a problem with the previous example: when we trigger the GO_TO_NEXT_PAGE
action, both the users
and articles
will handle that actions since they both are checking the same action name.
As you can guess, that can be solved by specifying different action names for different reducers, so weโll have the USERS_GO_TO_NEXT_PAGE
and ARTICLES_GO_TO_NEXT_PAGE
actions.
We can make that happen by passing a section parameter to the withPagination
higher order reducer:
Weโve seen the higher-order reducer pattern and how it solves code duplication and improves reusability by using function composition.
I hope youโve learned something new here, and that you can see how there are multiple patterns we can apply to Redux or our code in general given Reduxโs functional nature.
Stay cool ๐ฆ
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the โreport an issueโ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Great article, thanks!
A-MA-ZING! bring more of those please! Iโd say this is part of advance react topics