The Simplicity Of Writing Pure Functions

JavaScript, React, Redux

Lauren Cunningham
JavaScript in Plain English

--

Photo by Samara Doole on Unsplash

Intro to Pure Functions

Pure functions are highly favored as building blocks in functional programming due to their predictability and potential for being reused.

There are a couple of characteristics that define a function as ‘pure’.

  1. If given the same input, you will get the same output.
  2. No side-effects.

Predictable Output

We can pass an argument to a pure function and know that no matter how many times we run that piece of code, we will get the same result.
Check out this example below. No matter what we assign x to, we will get x squared back.

function getSquare(x) {
return x * x;
}

No Side-effects / Independent

Pure functions are always immutable. They should not change any outside variables. Consider the difference between mapping over an array and returning a new array versus using .push() to shovel a new item into an existing array. The ladder will alter the original array and is considered impure. The danger in altering shared states is that another function may have relied on that original state. Now that it has been changed, this can introduce bugs that may be hard to track down.

Purity Test

Let’s put this insight into action.
Which of these examples is pure and which is impure?

Option A:
function double(x) {
return x + x;
}
function doubleAll(list) {
return list.map(double);
}
Option B:
function double(x) {
networkCall(x);
return x + x;
}

function doubleAll(list) {
for (let i = 0; i < list.length; i++) {
list[i] = double(list[i]);
}
return list;
}

Answer:
Option A is pure! We can expect to get back a brand new array that has been created by mapping over the original array, but not mutating it in any way.

Option B is impure because it is dependent on the output of a network call and it is looping through a list of items to return an altered original list. If any other functions were dependent on that list, that could cause our program to crash or just not behave the way we intended it to.

React and Redux Usage

When working with React, your app can be made up of a combination of class and functional components. The difference is that functional components consist of pure functions and therefore do not hold any state. They should not mutate any external or shared state. Implementing functional components wherever you can is preferred for optimization as they are the simplest and most reusable of components. It’s also worth noting that these functional components are not meant to contain lifecycle methods.

One of the key principles of Redux is that it requires pure functions to update the global state tree with any incoming changes. We call these pure functions, reducers. They take the previous state and the action that we provide to return the next state, leaving the previous state unchanged.

In the diagram below, you can see how we update the state in Redux without altering the original state. We dispatch an action that is passed to the reducer. The reducer takes the information for the current state and uses a pure function to update the store with a new state based on the action we gave as an argument.

Brad Westfall @ css-tricks.com

In Closing

According to the Redux documentation, “writing immutable update logic by hand is hard, and accidentally mutating state in reducers is the single most common mistake Redux users make”.

There is a JavaScript library called Immer that takes our mutable code and converts it to an acceptable pure function. There’s even a special method called createSlice that you can use that incorporates Immer automatically. You can read more about it here.

Until then, it’s worthwhile to get comfortable with recognizing and formulating pure functions wherever you can for more optimized, reusable code.

Resources

What is a Pure Function
Pure vs. Impure Functions

--

--