Purity & Time in React

Rocky Meza
Everwise
Published in
3 min readApr 9, 2018

--

We all know that our render functions are supposed to be pure functions. Purity and immutable data are the basis for performance optimization in React.

That’s great until you need to use time in your app. Time presents some challenges for purity because time is always changing. This can be summed up by the following code snippet:

> new Date() == new Date()
false

In our system, we have lots of components that rely on the current time in order to render:

  • meetings are displayed differently if they’re upcoming or in the past
  • resources can become available at a certain time
  • due dates become more prominent as they are approaching
  • and more!

Imagine you had a component in your app that changed based on whether or not it’s the weekend.

Impure WeekendStatus implementation

When you render it on Tuesday, it outputs:

<p>It is not the weekend. :(</p>

When you render it on Saturday, it outputs:

<p>It's the weekend!<p>

This function is not pure because it uses new Date() to determine the current time. In React land, this is bad for many reasons:

  1. We cannot optimize the performance of our component because we cannot avoid reconciliation. Our render output changes sometimes regardless of whether or not the props have changed.
  2. If we open the page on Friday and leave it open until Saturday, the component will not update. Our component doesn’t know when to update.
  3. If we are using Jest snapshot tests, our snapshots no longer produce deterministic results. If we run our tests on Tuesday, they will not match the results if we run them on Saturday.
  4. Components could get out of sync just based on when they were rendered.

We need time in our apps, but we aren’t supposed to have impure render functions. How can we work around this?

The first step is to change <WeekendStatus> to take currentTime as a prop. This will make it a pure function which is easier to test and to optimize:

Pure WeekendStatus implementation

But how are we going to pass the currentTime to <WeekendStatus>? It would be annoying to have to pass currentTime down the tree to every single component that renders a <WeekendStatus>.

React Context to the rescue! With context, you can pass props down the tree implicitly, and you don’t have to deal with every single component on the way down. We can centralize the logic to get and update time into one place on the tree and then expose the current value to components underneath it.

At Everwise, we did just that and called it react-timeprovider.

Introducing React TimeProvider

<TimeProvider> uses the new React Context API in order to provide the current time to components that need it. Let’s see what that would look like.

Using TimeProvider

The <TimeProvider> component will put the currentTime in context and you can use <GetTime> to get the currentTime out of context.

This is better because now

  1. <WeekendStatus> is a pure function. React can optimize it.
  2. <TimeProvider> sets up an interval and will check the time every 500ms. Any components using <GetTime> will get updates whenever they need it.
  3. <TimeProvider> can be swapped out with a test version that returns the same date everytime. This makes snapshot testing easy:
    const MockTimeProvider = createTimeProvider(() => '2018–04–06T12:30:00Z');
  4. Because the cached time is stored in a centralized provider, all of the components on the page that use time will be in sync with each other. If you were rendering two <WeekendStatus> components, they would never give conflicting answers.

We went ahead and packaged <TimeProvider> into an NPM package. You can go download it here.

Implementing TimeProvider is straightforward with the new React Context API.

First import React:

import * as React from "react";

Next you have to create a context:

const TimeContext = React.createContext();

TimeContext is a simple object that contains two components: <TimeContext.Provider> and <TimeContext.Consumer>. We will wrap the <TimeContext.Provider> in our own component.

The TimeProvider component is fairly straightforward:

Simple TimeProvider implementation

The GetTime component is super easy to implement. In fact React already implemented it for us:

export const GetTime = TimeContext.Consumer;

We can even implement a HOC if you really want it:

That would then be used like this:

const WeekendStatusContainer = withTime(WeekendStatus);

Using <TimeProvider> helped us improve performance and also simplified many of our child components. You should use it too!

If you like using React, Everwise is hiring! We’re trying to make functional training nice and would like you to help us.

--

--