Understanding Pure Functions in React Functional Components: Importance and How to Implement

Understanding Pure Functions in React Functional Components: Importance and How to Implement

·

4 min read

You've probably heard the term "pure function" before, but if not, it's a function that follows two principles:

  1. No Side Effects: a pure function must not alter any objects or variables that exist before it's invoked

  2. Deterministic: a pure function must always return the same output when given the same set of inputs

In other words, you can tell if a function is "pure" if it's consistent and doesn't affect anything outside its scope.

An add function is a basic example of a pure function:

function add(a, b) {
    return a + b;
}

In the example above, the add function always returns the same result when you give it a specific set of inputs. 2 + 3 will always equal 5 (if for some reason it doesn't, then we probably have bigger problems).

React assumes functional components are pure

If your React components aren't pure functions, that'll likely lead to unpredictable and buggy applications. In other words, given the same set of props (i.e. inputs), your component should always return the same JSX (i.e. output).

Let's take a look at an example:

In the example above, the Banner component takes a name prop and displays a welcome message.

Given a specific value for the name prop, the JSX the Banner component returns will always be the same. If you pass the name Jack to the Banner component, it's impossible for the text to be anything other than Hello Jack!.

Impure components lead to inconsistent JSX

An impure component can lead to unexpected behavior:

This time, the Banner component takes a time variable defined outside of it and displays it along with the name. We use time % 12 to convert the time to a range between 1 - 12 and then add AM or PM to indicate whether it's morning or night.

However, because the first Banner component modifies the time component, the second Banner component shows AM instead of PM. When the first Banner component renders, it sets the time variable to 11 (i.e. 23 % 12 === 11), which the second Banner component then uses.

Note: If you run this with StrictMode enabled, it will actually show 11 AM for both Banners because React renders each component twice in a dev environment.

Access variables via props instead of via closures

In the example above, the Banner component has access to the time variable via a closure. Instead of doing this, you can fix the problem by just passing the time as a prop instead:

Mutating local variables is okay!

Remember, pure functions must not alter any objects or variables that exist before they're invoked. This means a pure function can update an object or variable that's created when it's invoked. In other words, you can update local variables all day long without making the function impure!

The following is perfectly acceptable:

type BannerProps = { name: string; time: number };

function Banner(props: BannerProps) {
    let time = props.time;
    if (time > 23) {
        time = 0;
    }

    const isPM = time > 11;
    time = time % 12;

    return (
        <p>
          Hello {props.name}, it's {time} {isPM ? "PM" : "AM"}!
        </p>
    );
}

In this example, if the time variable is greater than 23, we reset it back to 0. You can see that throughout the component, we're updating the time variable in several places. This is completely fine because the time variable was initialized inside the Banner component.

Why are pure components important in React?

Here are a few reasons why keeping your React components pure is beneficial:

  1. Predictability: Pure components are predictable, making debugging easier.

  2. Performance: Pure components are cacheable, which lets React optimize rendering (i.e. skip renders when inputs haven't changed).

  3. Server-Side Rendering: Pure components are deterministic, so your server can reuse them for many requests.

  4. Concurrent Mode: React can optimize rendering by pausing and resuming the render cycle without issues because pure components don’t rely on side effects.

It's important to make sure your components are pure. If you don't, your applications will be harder to maintain and less reliable in the long run!