The reduce function is an extremely powerful tool that is used to build new data sets from existing collections of data.
The reduce function is a higher-order function that accepts at least two arguments: a pure function and an initial state (of any data type). The pure function is evaluated recursively with the current list item and the previous state applied as arguments.
Redux uses the reduce pattern to create manageable state containers for application stores. Notice, that in the above example, that each time add is evaluated it returns the current state of the recursive process. In Redux, the add method would be referred as a “reducer” and the elements of the list could be thought of as actions; and the state could be thought of as the state of the application. The biggest difference is that in Redux, we don’t process lists of actions, actions are “dispatched”. Each time an action is dispatched the reducer (a pure function) is evaluated with the current state and the action object as arguments.
Functional composition is a way mapping the results of one function to the arguments of another. This is a useful tool, as it allows us create new abstractions by combining other abstractions. Composite functions are used in Redux to create middleware.
Using our knowledge of reduce and functional composition lets try to implemented some the methods found in Redux from scratch.
The store is the heart of Redux. Redux stores are made up of the following:
the state of the application
dispatch method, used to dispatch actions to the store
listener method, used to listen for state changes
reducer, a pure function used to change the state of store based on an action
getState method, which returns the current state of the store
While the store is made of many things, its implementation is quite simple and can be written in 20 or 30 lines of code.
As we have seen in the example above, the entire state of the application is determined by a reducer function that accepts two arguments: the current state and an action. Actions, tell the reducer how the application’s state should change and the reducer function returns the new state.
Using a single reducer works for most trivial applications but it doesn’t scale. As the application’s state tree grows, it becomes more difficult for the reducer to make state changes. The solution to this problem is to implement child reducers. This solution not works well for Redux, but implementing single minded functions is a good practice when working with complex datasets. So lets take at look at how to implement child reducers with Redux’s combineReducers function.
The combineReducers function accepts one argument, a key/value map. The key is the state field. The value is the child reducer. combineReducers maps the child reducer to the state field and returns a new reducer.
How does it work?
The implementation of combineReducers is quite simple and can be written is a few lines of code.
So lets implement a compose helper function that will allow us to easily preform function composition.
Now that we have a convenient way of composing functions, we can start to write the middleware layer for our Redux implementation.
We’re going to implement the applyMiddleware function. This function will create middleware that “sits” between the store’s dispatch method its action handler (a.k.a the reducer). So the data flow will look something like this: