javascript – Why are Redux's state functions called reducers?-ThrowExceptions

Exception or error:

This is a part the official Redux documentation:

It’s called a reducer because it’s the type of function you would pass
to Array.prototype.reduce(reducer, ?initialValue)

It doesn’t make much sense to me. Could somebody explain to me why they are actually called reducers? The fact that they return a default value (or they have a default argument value) doesn’t make them reducers IMHO.

How to solve:

The fact that they return a default value (or they have a default
argument value) doesn’t make them reducers IMHO.

Reducers do not just return default values. They always return the accumulation of the state (based on all previous and current actions).

Therefore, they act as a reducer of state. Each time a redux reducer is called, the state is passed in with the action (state, action). This state is then reduced (or accumulated) based on the action, and then the next state is returned. This is one cycle of the classic fold or reduce function.

As @azium summed up with state -> action -> state.

###

If you consider the series of actions in your app to be like a list, or maybe more like a stream, it might make more sense.

Take this contrived example:

['apple', 'banana', 'cherry'].reduce((acc, item) => acc + item.length, 0)

The first argument is a function of the form (Int, String) => Int. Along with an initial value, you pass reduce what might be called a “reducer function”, and you get the result of processing the series of items. So you might say, the reducer function describes what is done with each successive individual item to change the result. In other words, the reducer function takes the previously output and the next value, and it calculates the next output.

This is analogous to what a Redux reducer does: it takes the previous state and the current action, and it calculate the next state.

In true functional programming style, you can conceptually erase the meaning applied to the arguments and the result, and just focus on the “shape” of the inputs and output.

In practice, Redux reducers are typically orthogonal, in the sense that for a given action, they don’t all make changes to the same properties, which makes it easy to split their responsibilities and aggregate the output with combineReducers.

###

As already mentioned the name is related to the concept of a reducer in functional programming. You may also find the Merriam-Webster dictionary definition of reducer helpful:

1a. to draw together or cause to converge : consolidate (reduce all the questions to one)

The reducer consolidates actions into a single object representing application state.

###

The reason why a redux reducer is called a reducer is because you could “reduce” a collection of actions and an initial state (of the store) on which to perform these actions to get the resulting final state.

How? To answer that, let me define a reducer again:

The reduce() method applies a function (reducer) against an accumulator and each
value of the array (from left-to-right) to reduce it to a single
value.

And what does a redux reducer do?

The reducer is a pure function that takes the current state and an
action, and returns the next state. Note that the state is accumulated as each action on the collection is applied to change this state.

So given a collection of actions, the reducer is applied on each value of the collection (from left-to-right). The first time, it returns the initial value. Now the reducer is applied again on this initial state and the first action to return the next state. And the next collection item (action) is applied each time on the current state to get the next state until it reaches the end of the array. And then, you get the final state. How cool is that!

###

We know where Reducers are coming from (functional programming), and why they might be considered to be doing reducing work (reduce n input items to a single return value – which is just what normal functions are supposted do).
However: The name is just a name, like rose is the name for a rose. Do not think too much. Redux progammers are IT people, they are locked in their context and there it makes sense. The rest of us have to accept the inventor’s right to call a blue dog a yellow cat 😉

###

The author think state as the accumulator of the reduce function. Ex:

Final State = [Action1, Action2, ..., ActionN].reduce(reducer, Initial State);

The reduce function is coming from Functional Programming, the name “reducer” is also coming from FP.

I don’t like using that name here. Because I don’t see the world as a single value result after actions. The state here is an object. For example:

['eat', 'sleep'] === [addTodo('eat'), addTodo('sleep')].reduce(reducer, []);

This Reducer reduces nothing at all. And I don’t care it reduce anything or not. Naming it as Transducer will make more sense.

###

How about we call it Deducer from now on. It deduces the new state based on the previous state and the incoming action.

###

They should not be called reduce as reduce means to make less, these functions most often make more. and then return it

###

I couldn’t quite see how a Redux reducer directly mapped to the function you use with reduce, so here’s a couple of examples to see how they match up.

First a standard reducer (called ‘accumulator’ in MDN) function from the MDN Array.reduce documentation and then a simplified example of Dan Abramov’s Counter.js at the end of his ‘You might not need Redux’ blog post.

  • sum adds a value to the accumulator
  • reducer adds/subtracts a value to/from the accumulator.

In both cases here the ‘state’ is just an integer.

You are ‘accumulating’ the actions into the state. This is also the immutable way to modify any JavaScript object.

const sum = function(acc, val) {
    return acc + val;
};

const reducer = function(state, action) {
    switch (action) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
};

console.log('sum', [1, -1, 1].reduce(sum, 0));

console.log('reduce', ['INCREMENT', 'DECREMENT', 'INCREMENT'].reduce(reducer, 0));

console.log('sum', [1, 1, 1].reduce(sum, 0));

console.log('reduce', ['INCREMENT', 'INCREMENT', 'INCREMENT'].reduce(reducer, 0));

###

Other answers explain well why it’s named as it is but let’s try naming more things…

const origState = 0;
const actionOperators = {
    increment: (origState) => origState++,
    decrement: (origState) => origState--,
};
const anOperator = (aState, anAction) => actionOperators[anAction](aState);
const actions = ['increment', 'decrement', 'increment'];
const finalState = actions.reduce(anOperator, origState);

First, reduce could be called use anOperator with every action name and accumulated state, starting with origState. In smalltalk it’s called actions inject: origState into: anOperator.
But what do actually you inject into the operator? The origState AND the action names. So even in Smalltalk method names are not very clear.

actionOperators[increment] is a Reducer, but I would rather call it and actionOperator because it’s implemented for each action. The state is just an argument (and another one as return value).

Reducer is however a better word to be on top of google search results. It’s also similar to Redux.

###

In this code below you just need to think of the accumulator as the actions and currentValue as a state in redux context. with this example you will find out why they name it as a reducer too.

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// Main operation is 1 + 2 + 3 + 4 = 10
// but think of it as a stack like this: 

// | 2 | | 3 | | 4 | 
// |_1_| |_3_| |_6_| | 10 | => the 10 is in result

console.log(array1.reduce(reducer));
// expected output: 10

The reduce() method executes a reducer function (that you provide) on
each element of the array, resulting in a single output value.

Leave a Reply

Your email address will not be published. Required fields are marked *