Dissecting the reducer…

The above reducer code may look cryptic. To see what is going on, let’s consider what happens when I dispatch the ‘increment’ message:

dispatch(counter => counter.increment())

This is what gets dispatched to the reducer (the message is in bold):

{ type: 'MESSAGE', message: counter => counter.increment() }

Since the action type is MESSAGE, the reducer will execute this branch:

action.message(CounterModel)(state)

Which evaluates to this:

(counter => counter.increment())(CounterModel)(state)

Then the CounterModel will be injected into the message, and then evaluated:

(CounterModel.increment())(state)

Calling the increment() method on CounterModel results in this state-updating function:

(state => state + 1)(state)

It is then invoked with the counter’s current state in order to obtain the next state of the counter:

state + 1

Note that the message simply informs the recipient about the action that has taken place without mentioning the CounterModel. “To whom it may concern, the user wanted to increment the counter,” says the message.

Because CounterModel is behind the reducer, this means it can be hot-reloaded along with the reducer. When CounterModel is changed, the store can replay all the messages using the new reducer, and subsequently the new CounterModel. This wouldn’t work if CounterModel is mentioned directly in the dispatch call.