by rajaraodv

Why Redux need reducers to be “pure functions”

XT9DxopiX4SAvoCDesA4ESnp5McIav5Nw7oY

You may have heard that Redux depends on “pure functions” from functional programming. Well, what exactly does that mean?

The picture below shows a simple Todo app from Redux examples. It currently has four tasks. It shows the fourth one as completed, and is set to show “All” Tasks — both completed and not completed.

The right-hand side shows the current state stored in Redux. It’s a simple JavaScript object that captures all the details in one place.

That’s the beauty of Redux.

4eco4msoESVRWtcsEabWFpm0WWzxEO1gDURs
LEFT: Todo app ← →RIGHT: Redux stated

Now, let’s say you toggled the fourth task to be not-completed. Here’s what the app would look like with a new Redux state:

6WaOKohJOCgbgJGvAoYokKhcZR-wNmDYWVBc
Redux updates it’s state when the app changes

Now, if you look at the Reducer for “TOGGLE_TODO” — the one that toggles the status of a Todo item between completed and not completed — it looks like below (here’s the source code):

-jheepAaXFn835dchdmurqshr8-d1Dm7AVDV

When you toggle a Todo item’s state, this is what happens: the reducer function takes an object that represents the “old” state (i.e. input to a function), then creates a brand new object by copying all the old object’s details into a it (like id and text) and overriding old properties with new ones (completed prop).

Moec8tswLUsuI8-zFNT5gs-Y0HKMSAm6nqSe

Pure functions

At a fundamental level, any function that doesn’t alter input data and that doesn’t depend on external state (like a database, DOM, or global variable) and consistently provides the same output for the same input is a “pure” function.

For example, the below add function doesn’t alter “a” or “b”, doesn’t depending on external state, and always returns the same output for the same input.

const add = (a, b) => a + b //pure function

Now, if you look at our reducer function, it is a “pure” function as it has the same features.

But why should the reducer be a “pure” function?

Let’s see what happens if we make our reducer “impure.” Let’s comment out the section where it creates a new object, and instead let’s mutate the state’s completed prop directly.

case 'TOGGLE_TODO':      if (state.id !== action.id) {        return state;      }
            // return {      //   ...state,      //   completed: !state.completed      // }
      state.completed = !state.completed;//change original object      return state;
default: ...

Now if we try to toggle the TODO after this change, nothing happens!

Let’s see what’s going on in the Redux’s source.

lxQkKAq1x7nWzokdsojlcF9gjhQi3ZUNM38Z

Redux takes a given state (object) and passes it to each reducer in a loop. And it expects a brand new object from the reducer if there are any changes. And it also expects to get the old object back if there are no changes.

Redux simply checks whether the old object is the same as the new object by comparing the memory locations of the two objects. So if you mutate the old object’s property inside a reducer, the “new state” and the “old state” will both point to the same object. Hence Redux thinks nothing has changed! So this won’t work.

But, it still doesn’t answer some key questions like:

  • Why is Redux designed like this?
  • Why can’t Redux just make a copy of the old state some place else, then compare object props from reducers?
  • Why is Redux putting this burden on individual developers?

The answer: there is only one way to know if two JavaScript objects have the same properties. To deep-compare them.

But this becomes extremely expensive in real-world apps, because of the typically large objects and the number of times they need to be compared.

So one work around is to have a policy to ask developers to create a new object whenever there is a change, then send it to the framework. And if there are no changes, then send back the old object as it is. In other words, new objects represent new states.

Note that you must clone old states using slice — or a similar mechanism — to copy old values into a new object.

Now, with this policy in place, you can compare two objects’ memory location using !== without having to compare each property within each object. And if the two objects are not the same, then you know that the object has changed state (that is, some property somewhere in the JavaScript object has changed). That’s exactly the strategy Redux employs to make things work.

So that’s why Redux needs for “Reducers” to be pure functions!

Thank you for reading! If you liked the post please ? and share it on Twitter!??

React Performance:

  1. Two Quick Ways To Reduce React App’s Size In Production
  2. Using Preact Instead Of React

Functional Programming

  1. JavaScript Is Turing Complete — Explained
  2. Functional Programming In JS — With Practical Examples (Part 1)
  3. Functional Programming In JS — With Practical Examples (Part 2)
  4. Why Redux Need Reducers To Be “Pure Functions”

ES6

  1. 5 JavaScript “Bad” Parts That Are Fixed In ES6
  2. Is “Class” In ES6 The New “Bad” Part?

WebPack

  1. Webpack — The Confusing Parts
  2. Webpack & Hot Module Replacement [HMR] (under-the-hood)
  3. Webpack’s HMR And React-Hot-Loader — The Missing Manual

Draft.js

  1. Why Draft.js And Why You Should Contribute
  2. How Draft.js Represents Rich Text Data

React And Redux :

  1. Step by Step Guide To Building React Redux Apps
  2. A Guide For Building A React Redux CRUD App (3-page app)
  3. Using Middlewares In React Redux Apps
  4. Adding A Robust Form Validation To React Redux Apps
  5. Securing React Redux Apps With JWT Tokens
  6. Handling Transactional Emails In React Redux Apps
  7. The Anatomy Of A React Redux App
  8. Why Redux Need Reducers To Be “Pure Functions”
  9. Two Quick Ways To Reduce React App’s Size In Production

Salesforce

  1. Developing React Redux Apps In Salesforce’s Visualforce