Redux = Reduce + Flux

Jieren Chen
coderblurbs
Published in
4 min readDec 9, 2017

In order to understand Redux, we need to introduce two ideas: the reduce function and the Flux architecture.

Reduce

Functional programming is based around the idea that functions can be passed around as values, that they are first-class objects. Functions that take other functions as arguments are called higher order functions.

Operating on collections is a common use-case for higher order functions.

You should already be familiar with the map higher order function. map takes a list and a function of one argument. It then applies the function to each element of that list.

> [1, 2, 3, 4].map((a) => a + 1);
[2, 3, 4, 5]

In the example above, the function (a) => a + 1 will be applied to 1, 2, 3, and then 4, resulting in 2, 3, 4, 5 respectively.

Another commonly used higher order function is filter. Just like map, filter takes a list and a function of one argument. The function here must return either true or false and the filter will return all elements of the list that return true when evaluated by the function.

> [1, 2, 3, 4].filter((a) => a % 2 == 0);
[2, 4]

The higher order function we’re most interested in is reduce. This one is a bit more complicated. It feeds a list into an accumulator, with a function to decide what each element does to the accumulator.

> [1, 2, 3, 4].reduce((a, b) => a + b, 0);
10

Think of it as a conveyer belt.

First element is presented to the function. The function is evaluated with (acc, ele), i.e. (0, 1)
The return value of the function becomes the new accumulator.
The next element is presented to the function and it is evaluated with (1, 2).

In fact all higher order functions can be implemented as a reduce. Let’s take filter for example.

const filter = (list, filt) => {
return list.reduce((acc, next) => {
if (filt(next)) {
return acc.concat(next);
} else {
return acc;
}
}, []);
}

Exercise for the reader to figure out what’s going on here.

Flux

Flux is a bit more complicated to explain. I recommend taking a look at the original Flux presentation by Jing Chen to fully understand its motivations.

Flux is intended to solve the flow of data problem in frontend applications.

As we discussed previously, frontend applications depend on asynchronous user actions. This can get very complicated as user actions can feed into views that then feed back into other user actions. This became a big problem with MVC where a single model could be tied to multiple views and vice versa.

Having the caller drive the action is a PITA (see callback hell.)

What if you could use a single direction data flow using messages? A user initiates an action, which creates a message sent to the dispatcher, which modifies the store based on some business logic, which then modifies the view based on some display logic.

Example from the dispatcher docs:

A message (action) is presented to the dispatcher
There are a number of store functions registered with the dispatcher. The dispatcher forwards the message to the relevant store functions.
The store function then modifies a store. In the case of React, it would update the state of a component. The important thing here is that only one change to the store happens at a time.

Redux

What you may have noticed is how similar the Flux flow is to the reduce function. Things (action messages) are presented (dispatcher) to a function that then makes a modification to an accumulator (store).

Redux dispenses with the dispatcher in favor of reducers. Reducers are reduce functions that consume an action at a time.

Where Redux comes in is by using reducers to modify the store one message at a time. Reducers are pure functions that can modify the store predictably.

Let’s take the example from the Redux docs.

function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

Whenever this reducer gets an INCREMENT message, it will return the current state with 1 added to it. This will then become the new current state. This is just like what happened with our reducer on a collection, except now we’re operating on a stream of events.

So with Redux, our architecture looks similar to the reduce function, something like this:

When we generate a message, we send it to every reducer for the app. These reducers can choose to ignore the message or use it to modify its state. Thus state modification under Redux becomes message processing.

--

--

Jieren Chen
coderblurbs

Merging high brow and low brow into some kind of uni-brow.