Purity is an important concept when it comes to talking about functional programming. A pure function can be described by two characteristics

  • Produces no side effects
  • Given the same input, it always returns the same output

Using pure functions is the easiest way in which you can reduce the cognitive load of understanding your code and make it simpler for other developers to get up to speed quickly.

Side efffects

Side effects in programming occur when a function changes elements that are outside of its scope. Let’s take a look at an example of a function that produces side effects.

const names = ['Tommy', 'Mike', 'Anna']

const addName = newName => {
  names.push(newName)
}

addName('David')

// names = ['Tommy', 'Mike', 'Anna', 'David']

As you can see after we execute the addName the underlying global variable names changes. The variable is not local to the addName, hence the function has created a side effect.

Let’s take a look at an example of a function that doesn’t produce any side effects.

const names = ['Tommy', 'Mike', 'Anna']

const addName = (newName, names)=> {
  return [...names, newName]
}

const newNames = addName('David', names)

// newNames = ['Tommy', 'Mike', 'Anna', 'David']

We have changed the addName function by adding an extra argument and the internal code block in which the appending itself happens. Now the function doesn’t depend on any global variables. We’re also not modifying any arguments passed in. Our function now creates a new array of the desired shape.

Input/Output

Let’s now consider the Input/Output criteria. Take a look at the below example.

const addNumber = (number) => {
  const randomNumber = Math.floor(Math.random() * 10);
  return randomNumber + number
}

addNumber(9)
// ???

Can you predict the output of the addNumber function? Well, I can’t.

Every time we run addNumber it generates a random integer between 0 and 9. We then return the sum of that number with the argument passed into the function. So it doesn’t matter if we always provide the same input, we can never predict the output.

Let’s make this function pure.

const addNumber = (number) => {
  const a = 8
  return a + number
}

addNumber(9)
// 17

Now that we have removed all of the randomnesses we can predict the output of the function. The number argument will always be incremented by 8. It doesn’t matter how many times we call it.

React components

You can probably see where this article is going. We can apply the same principles of purity to React components. Such a component always renders the same output gives the same props and state. This principle applies to both functional and class components.

Let’s write our first pure functional component.

const Header = ({ portal }) => {
  return (
    <h1>Welcome to {portal}!</h1>
  )
}

export default Header

// <Header portal='Upmostly'/> => Welcome to Upmostly!

As you can see, it doesn’t matter how many times we call this component. Given the same state (or lack of it in this case) and props, it will always render the same HTML h1 element to the DOM.

Now let’s see how the Header component would look like if it was written as a class.

class Header extends React.Component {
  render() {
    return <h1>Welcome to {this.props.portal}!</h1>
  }
}

export default Header

The class-based components can also be made pure by extending React.PureComponent instead of React.Component

class Header extends React.PureComponent {
  render() {
    return <h1>Welcome to {this.props.portal}!</h1>
  }
}

export default Header

// <Header portal='Upmostly'/> => Welcome to Upmostly!

Tada! It’s quite simple.

The biggest advantage that comes from using pure components is that our application becomes much faster!

Avatar photo
πŸ‘‹ Hey, I'm Dawid Budaszewski
Hello! I'm Dawid. I'm a full-stack developer with a couple of years of experience under my belt. I spent most of my career working with React. Now it's time to pass the knowledge onto somebody else!

πŸ’¬ Leave a comment

Your email address will not be published.

We will never share your email with anyone else.