Click here to Skip to main content
15,886,003 members
Articles / Programming Languages / Javascript

What is a Redux reducer?

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
27 May 2018CPOL4 min read 2.4K   1   1
What is a Redux reducer?

reducer, n. – A word Redux made up to confuse you.

In order to write Redux code, you need to know a few things. One of those things is what a reducer is and what it does. It might seem a bit scary and foreign, but after this short article, I think you’ll come to agree that it is, as the saying goes, “just a function.”

First off, where does the name “reducer” come from? Redux didn’t actually make it up (I was kidding about that). It might not seem too foreign if you’re familiar with functional programming and JavaScript’s Array.reduce function. And if you know Array.reduce, you know that it takes a function (one might call it a “reducer” function) that has the signature (accumulatedValue, nextItem) => nextAccumulatedValue.

Array.reduce is like a Sister to Redux

If you aren’t yet familiar with Array.reduce, here’s what’s up:

JavaScript’s Array has a built-in function called reduce.

(Technically, I should be writing it as Array.prototype.reduce, because it is a function on array instances, not on the capital-A Array constructor.)

It takes a function as an argument, and it calls your provided function once for each element of the array, similar to how Array.map works (or a for loop, for that matter). Your function gets called with 2 arguments: the last iteration’s result, and the current array element. This will make more sense with an example:

JavaScript
var letters = ['r', 'e', 'd', 'u', 'x'];

// `reduce` takes 2 arguments:
//   - a function to do the reducing (you might say, a "reducer")
//   - an initial value for accumulatedResult
var word = letters.reduce(
  function(accumulatedResult, arrayItem) {
    return accumulatedResult + arrayItem;
  },
''); // <-- notice this empty string argument: it's the initial value

console.log(word) // => "redux"

In this example, the reducer will get called 5 times (because there are 5 elements in the array). The calls go like this:

  • first called with ('', 'r') => returns 'r'
    • the empty string '' comes from the 2nd argument to reduce, and the 'r' is the first element of the array
  • then ('r', 'e') => returns 're'
    • the ‘r’ comes from the previous return value, and ‘e’ is the next element of the array
  • then ('re', 'd') => returns 'red'
    • the ‘re’ is the previous return value, and ‘d’ is the third array element
  • then ('red', 'u') => returns 'redu'
    • by now, you are sensing a pattern
  • then ('redu', 'x') => returns 'redux'
    • the pattern is all too clear now

The last return value, 'redux', is returned as the final result and stored in the word variable.

Redux Reducers

Now that you know how Array.reduce works, I can tell you that Redux is basically a fancy Array.reduce function (ok ok, that’s a huge oversimplification, but bear with me).

A Redux reducer function has this signature:

(state, action) => newState

As in: it takes the current state, and an action, and returns the newState. Looks a lot like the signature of an Array.reduce reducer, eh? Remember:

(accumulatedValue, nextItem) => nextAccumulatedValue

Plainly speaking, a Redux reducer gets to decide how each action affects the state. Let’s look at an example one:

JavaScript
function wordReducer(state = '', action) {
  switch(action.type) {
    case 'ADD_LETTER':
      return state + action.letter;
    case 'RESET':
      return '';
    default:
      return state;
  }
}

Quick quiz: Is there any Redux-specific code in here? Anything that depends on the Redux library to work? Go ahead, think it over, I’ll wait.

Answer: Nope! This is a plain old function. Sure, it takes (state, action) arguments and returns a new state. And it expects action to look something like {type: 'ADD_LETTER', letter: 'r'}. But none of that is particularly bound to Redux.

How It Works

But anyway, what does it actually do? Let’s try calling it with a few things and see what it returns.

JavaScript
let state = '';
console.log(wordReducer(state, {type: 'ADD_LETTER', letter: 'y'}));
  // => y
console.log(wordReducer(state, {type: 'ADD_LETTER', letter: 'y'}));
  // => y
console.log(wordReducer(state, {type: 'ADD_LETTER', letter: 'y'}));
  // => y

First: Notice that wordReducer does not remember anything. It holds no state within.

JavaScript
let state = '';
console.log(wordReducer(state, {type: 'ADD_LETTER', letter: 'a'}));
  // => a
console.log(wordReducer(state, {type: 'ADD_LETTER', letter: 'b'}));
  // => b
console.log(state)
  // => ''

Next: Notice that wordReducer does not change the state. It merely returns a new one. It treats state as immutable. This is important because, by updating state in an immutable way, Redux is able to tell which pieces of state changed, and optimize how your app is re-rendered.

One more thing:

JavaScript
console.log(wordReducer(undefined, {type: 'UNHANDLED'}));
  // => ''
console.log(wordReducer('existing state', {type: 'UNHANDLED'}));
  // => 'existing state'

Notice that the reducer has an initial state (when given undefined, it returns an empty string anyway), and that it has a default case that handles any actions it doesn’t understand (it returns the existing state, unchanged, when it sees such an action).

Pilot Needed

I can tell you don’t think this is very useful. What good is a function that doesn’t remember anything, and doesn’t change anything?

I’ll tell you: This function is nice because it is predictable. If you call it with the same arguments, you get the same outputs, every single time. It doesn’t matter what else has changed in your app – this function will always act the same way.

It is easy to figure out what it does by reading its code (and easy to debug!) because it’s all self-contained.

Now, the downside with a function like this is that it needs a driver of sorts. Something needs to hold on to the intermediate state, otherwise the app won’t really do much of anything.

The driver, in this case, is Redux. Specifically, the Redux store. It does something like this:

JavaScript
let state = '';
state = wordReducer(state, {type: 'ADD_LETTER', letter: 'a'}));
state = wordReducer(state, {type: 'ADD_LETTER', letter: 'b'}));
state = wordReducer(state, {type: 'ADD_LETTER', letter: 'c'}));

The store maintains an internal state variable. When an action is dispatched, the store calls the reducer, and replaces its internal state with whatever the reducer returned. Every time the store calls the reducer, it passes in the last-known state.

Around and around it goes: Redux sitting there waiting for an action, handling that action, updating the state, re-rendering your app, on and on forever.

So that’s it! That’s how Redux reducers work, in a nutshell. Not too bad?

This article was originally posted at https://daveceddia.com/feed.xml

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Dave is a Software Engineer in the Boston area and writes about AngularJS and other JavaScript things over at daveceddia.com

Comments and Discussions

 
GeneralMy vote of 5 Pin
Sebastiaan Meijerink19-Jun-19 3:44
professionalSebastiaan Meijerink19-Jun-19 3:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.