93

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.

SOLO
  • 868
  • 9
  • 19
Anton Savchenko
  • 1,210
  • 1
  • 8
  • 11
  • 6
    They are reducers exactly because they behave like the function you pass to `reduce`, which has access to the default value and another value, and gives you back your potentially transformed default value. `state -> action -> state` – azium Dec 19 '15 at 22:40
  • 2
    a rose by any other name... probably marketing; map/reduce is a buzzword now... – dandavis Dec 19 '15 at 22:54
  • 1
    that;s why you must start to think yourself and don't rely on a framework. A framwork is mostly work of one or a few developers with their own vision how to solve a problem adapted by internet users. Some frameworks got it right however mostly don't. a blizz of a kiss, the same or less is not a solution. This is just an example of many out there. – Codebeat Aug 24 '18 at 02:09

11 Answers11

79

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.

Davin Tryon
  • 66,517
  • 15
  • 143
  • 132
  • 8
    Humm by this logic shouldn't they be called increasers rather than reducers? No data is ever being reduced its being added :/ lol – Jamie Hutber Jun 11 '16 at 23:25
  • 20
    @JamieHutber I think you slightly miss the meaning of reducer in this context. reducer is taking a stream (or collection) of items and combining them into a single item. In this case, all actions (through time) are the collection of items, and the state is the single item. Make sense? – Davin Tryon Jun 12 '16 at 11:01
  • 8
    lol I see now. So its basically just concating them. Why not call it merger then :P THanks for making it clear to me :) – Jamie Hutber Jun 12 '16 at 22:41
  • 25
    Thank goodness I am not the only one thinks the name reducer is a bit off at least 2,000 views on this post at the time I write this. The fact that someone is even willing to spin up the effort to dig up why it is called reducer doesn't it imply it is indeed a bit off ? If It's called a reducer because it's the type of function you would pass to Array.prototype.reduce, it is like let's call orange a juicer because we pass orange to object.prototype.juicer, or shouldn’t we call it a fruit ? – Yini Jan 08 '17 at 02:58
  • 3
    I agree, it's not at all an intuitive name. Logically, to be called reducer it should reduce something. If it took a whole array of state changes along with a state and combined them into a single state all at once, then it would be an intuitive name. – Peter Evan Deal Nov 13 '18 at 16:09
  • 1
    @JamieHutber by idea they are reducing the size of the array they are applied to. You can think of them as sort of filters + shared context (aka aggregator or state) where one can post his totals or whatever one might need. In the general case they reduce an array of data to a single value(s) like a total. – Deian Jan 16 '20 at 15:15
  • At this point, the term `(state) reducer` just is what it is - even though it confuses me every time. I process it in my mind as a `state transition function`. – vaughan Feb 28 '21 at 23:15
  • `f(old_state, action) => new_state` An example would be `f(apple_state_green, change_color) => apple_state_red` Here I would chose to name `f` as `stateChanger` instead of `reducer`. We are not reducing 5 apples to 3 apples. We are changing apple's state from green to red as defined in the state change action definition. – Mehmet Kaplan May 28 '21 at 07:40
  • @MehmetKaplan in the JavaScript `reduce` function the callback is the signature: `(acc, next) => acc`. The result of the reduce could be any number of transformations. In general terms, a transition from green to red is a reduction. You are taking an old state `green` and a new state `red` and *reducing* them to the next state `red`. – Davin Tryon May 28 '21 at 07:45
  • @DavinTryon, I guess you are referring to the `reduce` function of the arrays (not the objects as general). That reduces N elements of an array to a single value. Its purpose, as far as I interpret, is not to convert an array to another array. In redux, we are trying convert a state to another state, which is in simplest form, change of state. (On the other hand, I agree naming is hard and there is no method to satisfy all.) – Mehmet Kaplan May 28 '21 at 08:36
20

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.

acjay
  • 34,571
  • 6
  • 57
  • 100
  • Yes, you're right, it makes more sense when I'm thinking about actions more like about a stream. Cool, apretiate that! – Anton Savchenko Dec 20 '15 at 22:39
  • This was how I initially understood it, but this doesn't seem to be how any of the store implementations I've seen thus far have implemented it... – Boris Callens Feb 06 '17 at 21:09
16

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.

Drew Goodwin
  • 832
  • 9
  • 15
8

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!

code4kix
  • 3,937
  • 5
  • 29
  • 44
6

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.

joshmori
  • 438
  • 6
  • 11
5

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 ;-)

René Baron
  • 115
  • 1
  • 5
2

It is, arguably, a poor choice of naming. (Subjective comment, no offence, I agree naming is hard and you can not make everybody happy at the same time.)

I know people, just because of this naming, had hard time to adapt the redux. When I told them, it is a simple "state changer" then everything magically became fine. So rather than using the word reducer, we started using stateChanger as the reducers' function names.

Trivia:

From computer science perspective, a reduction is employing an algorithm of a problem to solve another problem (solving one can solve the other as well). For example SAT class problems reduce to the 3SAT class. It means all SAT problems can be solved by a solver of the 3SAT class problems. (For whom the bell tolls - or simply interested - you can refer to the greatest living mind Scott Aaranson's lecture on the subject) As you see the reducing here has nothing to do with redux's reducers.

Our approach:

On the other hand, redux's play area is more like the "state machines". So a reducer is actually a state changer function. That is why we, in our company, are using the stateChanger naming in order to avoid thinking about what the function was doing each time. (Yes that few milliseconds are what we are trying to avoid, because it sometimes annoys us because we lose our concentration on the main problem. And since redux is the heart of the data on the presentation layer, we came the same position frequently and avoiding even milliseconds is valuable for us.)

Mehmet Kaplan
  • 1,723
  • 2
  • 20
  • 43
2

Calling Redux reducers reducers is semantically incorrect and doesn't make much sense. That's why the author is confused.

A reducer is a function that reduces a set of values to a single value.
We can also say that it folds the values - thus the classic fold() fn in functional programming.

Since Redux reducer does not fold a set of values, but applies an action to a state and always returns the same shape (State -> Action -> State) - it should be called applicator or applier.
But, since we have to always return the same shape of the state, and not just smth completely unrelated - we'd make much more sense calling Redux state applicators changers, transformers or mutators.
And, it indeed has become commonplace to use terms like 'mutate the state' and 'state mutator'.

But Redux sounds just so much cooler, than Applux or Mutux :)

avalanche1
  • 3,154
  • 1
  • 31
  • 38
1

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.

Rivenfall
  • 1,189
  • 10
  • 15
1

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));
icc97
  • 11,395
  • 8
  • 76
  • 90
1

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.

Ehsan Ahmadi
  • 1,382
  • 15
  • 16