Why is a Redux reducer called a reducer?

11,283

Solution 1

The term "reduce" is actually a functional term used in functional programming. In a language like Haskell, F# or even JavaScript, we define a transformation that takes a collection (of any size) as input and returns a single value as output.

So (not to be pedantic, but I find this helps me) think of it visually. We have a collection:

[][][][][][][][][][]

...which we want to collapse into a single value:

N

Programming functionally, we would do this with a single function that we could call recursively on each element of the collection. But if you do that, you need to keep track of the intermediate value somewhere, right? Non-pure implementations might keep some kind of "accumulator" or variable outside of the function to keep track of the state, like so:

var accumulator = 0;
var myArray = [1,2,3,4,5];

myArray.reduce(function (each) {
    accumulator += 0;
});

return accumulator;

With pure functions, though, we can't do this - because by definition, pure functions can't have effects outside of their function scope. Instead of relying on an external variable that encapsulates our "state" between calls, we simply pass the state along in the method:

var myArray = [1,2,3,4,5];

return myArray.reduce(function (accumulator, each) {
    return accumulator + each;
}, 0);

In this case we call the function a "reducer" because of its method signature. We have each (or current - any name is fine), representing an object in the collection; and state (or previous), which is passed to each iteration of the function, representing the results of the transformation we've already done to the previous elements in the collection.

Note that the MDN documentation you referenced is correct; the reduce() function always does return a single value. In fact, the reduce method in any language is a higher-order function that takes a "reducer" (a function with the method signature defined above) and returns a single value. Now, yes, you can do other stuff with it, if your function that you call has side effects, but you shouldn't. (Essentially, don't use .reduce() as a foreach.) Even if the method you call with reduce has side effects, the return value of reduce itself will be a single value, not a collection.

The cool thing is, this pattern doesn't just have to apply to arrays or concrete collections, as you've seen in React; this pattern can be applied to streams as well, since they're pure functions.

Hope this helps. For what it's worth, the definition on the Redux site could be improved (as the concept of a reducer isn't just because of Javascript's Array prototype method). You should submit a PR!

Edit: There's a Wikipedia article on the subject. Note that reduce has different names, and in functional languages, it's commonly known as Fold. https://en.wikipedia.org/wiki/Fold_(higher-order_function)#Folds_as_structural_transformations

Edit (2020-10-03): People still seem to be finding this useful - that's good. With time, I've realized that "fold" is a much better term for this; the functional languages got it right. "Reducer" isn't really a bad term, but it's not necessarily a good one, either.

Solution 2

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!

Solution 3

Sorry, but I would disagree with previous answers. I would not support the naming reducer. I'm passionate about FP and immutability. Don't blame me, read the second part, but I want to state first, why I disagree.

It's correct that the reducers are the sequence of transformations, but the sequence itself - could be part of another sequence. Imagine it, like links - a part of chain. But the chain itself could be part of longer chain. Each link is the "transition" of the global state. Than, what the theory behind it?

Isn't it actually the "Finite state machine"? - close, but not. It's actually the Transition system.

A labelled transition system is a tuple (S, Λ, →) where S is a set of states, Λ is a set of labels and → is a set of labelled transitions

So, S - are set of our states

Λ - is our so-called "actions" (but labels in theory)

... and

- reducers "labelled transitions"! I would name it so, if I am creator of this library.

Understanding this theory helped me to implement my library, where I can have low-level transition system as a part of high-level transition system (like chain - still could be part of longer chain) - and still having single global Redux state.

Solution 4

I'm under the impression that a reducer in Redux is responsible for modifying state. An example reducer:

const count = function(state, action) {
    if (action.type == 'INCREMENT') {
        return state + 1;
    } else if (action.type == 'DECREMENT') {
        return state - 1;
    } else {
        return state;
    }
}

... I don't see how this is a function that would be passed to reduce. How is that data being reduced to a single value? If this is a function you would pass to reduce then state would be the callback and action would be the initial value.

// count function from your question
const count = function (state, action) {
    if (action.type == 'INCREMENT') {
        return state + 1;
    } else if (action.type == 'DECREMENT') {
        return state - 1;
    } else {
        return state;
    }
}

// an array of actions
const actions =
  [ { type: 'INCREMENT' }
  , { type: 'INCREMENT' }
  , { type: 'INCREMENT' }
  , { type: 'INCREMENT' }
  , { type: 'DECREMENT' }
  ]

// initial state
const init = 0
  
console.log(actions.reduce(count, init))
// 3 (final state)
// (INCREMENT 4 times, DECREMENT 1 time)

Solution 5

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 value, 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 has indeed become commonplace to use terms like 'mutate the state' and 'state mutator'.

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

Share:
11,283

Related videos on Youtube

BugHunterUK
Author by

BugHunterUK

Updated on February 04, 2022

Comments

  • BugHunterUK
    BugHunterUK over 2 years

    Whilst learning Redux I've came across Reducers. The documentation states:

    The reducer is a pure function that takes the previous state and an action, and returns the next state. (previousState, action) => newState. It's called a reducer because it's the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue) .

    MDN describes the reduce method as:

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

    I'm still confused on why the Redux definition of a reducer as it's making no sense. Secondly the MDN description doesn't seem correct either. The reduce method isn't always used to reduce to a single value. It can be used in place of map and filter and is actually faster when used in place of chaining.

    Is the MDN description incorrect?

    Jumping back to the Redux definition of a reducer, it states:

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

    I'm under the impression that a reducer in Redux is responsible for modifying state. An example reducer:

    const count = function(state, action) {
        if(action.type == 'INCREMENT') {
            return state + 1;
        } else if(action.type == 'DECREMENT') {
            return state - 1;
        } else {
            return state;
        }
    }
    

    ... I don't see how this is a function that would be passed to reduce. How is that data being reduced to a single value? If this is a function you would pass to reduce then state would be the callback and action would be the initial value.

    Thanks for any clear explanations. It's difficult to conceptualize.

    • code4kix
      code4kix almost 7 years
      Great question!
    • MattE
      MattE almost 5 years
      To me, coming from WPF and C#, actions seem to be athe "setter" action and reducers are the "getter" action. While not actually functioning this way under the hood because it returns a completely new state object instead of changing it, but the end result is similar to what it accomplishes.
    • Saeed Neamati
      Saeed Neamati almost 3 years
      As a developer with over 15 years of experience in Java, .NET, Android, Angular, PHP, and other stacks, I can for sure say that namings in redux are simply a disgrace to the development community. Redux developers should be ashamed of themselves for confusing generations of developers.
    • JBallin
      JBallin over 2 years
      Regarding your challenge of the MDN definition, can you provide an example where a reducer does not return a single value? Remember that an Array is still a single value. Certainly reduce can be used in place of map/filter, but it's different in that you're working off of one value (the accumulator) instead of operating on each element in isolation.
    • JBallin
      JBallin over 2 years
      Regarding your 2nd to last paragraph, the entire reducer function gets passed as the "reducer" - the "initial value" is a separate parameter.
  • zerkms
    zerkms over 7 years
    "the return value of reduce itself will be a single value, not a collection." --- this needs re-wording. There is nothing wrong in returning a collection. Fold is a more powerful operation than any other collection-based so you can express everything else with just it.
  • jedd.ahyoung
    jedd.ahyoung over 7 years
    @zerkms Ehh, yeah, I suppose you're right. You could return a "collection", but...hmm. Wonder what a good way to word that is. I suppose you're returning the final state of the full transformation, which is "one" state.
  • zerkms
    zerkms over 7 years
    It's folding :-) (a -> b -> b) -> b -> [a] -> b --- here is a signature from haskell. So the return type b can be anything, including [a]. So for that very reason I slightly don't like the term "reducer", since it never changes the shape of the state (it can but only crazy would do that).
  • jedd.ahyoung
    jedd.ahyoung over 7 years
    @zerkms Feel free to edit the question, if you think that you can add valuable information and teach the concept well. I think it's good to tie into the OP's question about the "reducer" terminology, though. If your edit is substantial, I'll make this a community wiki.
  • jedd.ahyoung
    jedd.ahyoung over 7 years
    @zerkms I've been thinking about a better way to describe this. Do you think it's accurate to say that you can "build a return value" (regardless of type - an atom or a collection) based on an existing set?
  • zerkms
    zerkms over 7 years
    I'm not sure. The variable/binding with a result is often called "an accumulator". But using "to accumulate" there looks awkward. Just leave it as is, and these comments would be a clarification :-)
  • Ellery Familia
    Ellery Familia about 6 years
    I've been struggling with the library simply because I just can't get pass the 'reducer' nomenclature... it's actually helpful for me to know that others struggle with the name as well. @code4kix definition above also helped
  • Tushar Pandey
    Tushar Pandey almost 5 years
    i think its same as semi-automatic washing machine vs automatic washing machine , in first we have to maintain its state for drying the clothes but in another be get the result output it maintain its state internally.
  • zameb
    zameb about 3 years
    Interesting. Still strange that Redux reducers receives 2 params, with different meanings. The concept would fit more if those 2 params were similar to "reduce" something into another "thing". Another point yet is that it is nothing special to return a "single value", in OOP thats common in most functions... another one yet, the function sum(a, b) { return a + b; } would fit in the "reducer" definition. Something that old and basic, deserving a new naming, is a bit estrange. In my opinion, all the Redux naming is misguiding and too forced.
  • tobius
    tobius almost 3 years
    By any chance do you know when the term "reduce" was first used and in which language? If I figure it out before someone else answers I'll post it back here. I would love to be able to point to a historical moment in time when the term "fold" was first misrepresented as "reduce" so that we can first explain when it was incorrectly (IMO) renamed to "reduce", and then continue to explain the "fold" pattern instead of the "reduce" pattern.
  • Saeed Neamati
    Saeed Neamati almost 3 years
    As a developer with over 15 years of experience in Java, .NET, Android, Angular, PHP, and other stacks, I can for sure say that namings in redux are simply a disgrace to the development community. Redux developers should be ashamed of themselves for confusing generations of developers.
  • Derek Greer
    Derek Greer over 2 years
    I agree with Saeed Neamati. This is pretty horrible. The term "reduce" makes sense when used for its original purpose (i.e. aggregation), but it doesn't make sense to apply to functions which don't aggregate, but just take a single value and transform into a new value. React's explanation that reducers "reduce a set of actions (over time) into a single state" is an absurd attempt to try to make the term fit.
  • Purplejacket
    Purplejacket over 2 years
    I like this answer because it visually (in a table) compares the method signatures of Array.reduce and the Redux notion of reduce, which is the key similarity for the naming convention.
  • Purplejacket
    Purplejacket over 2 years
    Also: This answer gives a link to the Redux docs which now thoroughly discuss this question. Excellent.
  • Ashique Desai
    Ashique Desai over 2 years
    What a wonderful answer. Thanks for this. Reducer isn't an accurate name - but as you said - Applux, Mutux would sound horrible. Appropriate naming convention and marketing don't go together, I guess!