State Management: How to tell a bad boolean from a good boolean

mattpocockuk

Matt Pocock

Posted on May 27, 2021

State Management: How to tell a bad boolean from a good boolean

TL;DR: Bad booleans represent state. Good booleans are derived from state.

When you're managing state in your app, it's easy to fall prey to bad booleans. Bad booleans look like this:

let isLoading = true;
let isComplete = false;
let hasErrored = false;
Enter fullscreen mode Exit fullscreen mode

On the surface, this looks like good code. It appears as though you've represented three separate states with proper boolean names. In the 'model' you've pictured for your state, only one of these states can be true at any one time.

In a fetch request, you might model the state like this:

const makeFetch = async () => {
  isLoading = true;
  try {
    await fetch('/users');

    isComplete = true;
  } catch (e) {
    hasErrored = true;
  }
  isLoading = false;
};
Enter fullscreen mode Exit fullscreen mode

Again, this looks nice. We're orchestrating our booleans as we move through the async request.

But there's a bug here. What happens if we make the fetch, it succeeds, and we make the fetch again? We'll end up with:

let isLoading = true;
let isComplete = true;
let hasErrored = false;
Enter fullscreen mode Exit fullscreen mode

Implicit states

You probably hadn't considered this when you made your initial model. You may have frontend components which are checking for isComplete === true or isLoading === true. You might end up with a loading spinner and the previous data showing at the same time.

How is this possible? Well, you've created some implicit states. Let's imagine you considered 3 states as ones you actually wanted to handle:

  1. loading: Loading the data
  2. complete: Showing the data
  3. errored: Erroring if the data doesn't turn up

Well, you've actually allowed 8 states! That's 2 for the first boolean, times 2 for the second, times 2 for the third.

This is what's known as boolean explosion - I learned about this from Kyle Shevlin's egghead course.

Making states explicit

How do you get around this? Instead of a system with 8 possible values, we need a system with three possible values. We can do this in Typescript with an enum.

type Status = 'loading' | 'complete' | 'errored';

let status: Status = 'loading';
Enter fullscreen mode Exit fullscreen mode

We'd implement this in a fetch like this:

const makeFetch = async () => {
  status = 'loading';
  try {
    await fetch('/users');

    status = 'complete';
  } catch (e) {
    status = 'errored';
  }
};
Enter fullscreen mode Exit fullscreen mode

It's now impossible to be in the 'loading' and 'complete' state at once - we've fixed our bug. We've turned our bad booleans into a good enum.

Making good booleans

But not all booleans are bad. Many popular libraries, such as react-query, apollo and urql use booleans in their state. An example implementation:

const [result] = useQuery();

if (result.isLoading) {
  return <div>Loading...</div>;
}
Enter fullscreen mode Exit fullscreen mode

The reason these are good booleans is that their underlying mechanism is based on an enum. Bad booleans represent state. Good booleans are derived from state:

let status: Status = 'loading';

// Derived from the status above
let isLoading = status === 'loading';
Enter fullscreen mode Exit fullscreen mode

You can safely use this isLoading to display your loading spinner, happy in the knowledge that you've removed all impossible states.

Addendum: Enums in Javascript

A couple of folks in the comments are asking how we represent a state enum in Javascript. While the above code will work without typings, you can also represent enums as an object type.

const statusEnum = {
  loading: 'loading',
  complete: 'complete',
  errored: 'errored',
};

let status = statusEnum.loading;

const makeFetch = async () => {
  status = statusEnum.loading;
  try {
    await fetch('/users');

    status = statusEnum.complete;
  } catch (e) {
    status = statusEnum.errored;
  }
};
Enter fullscreen mode Exit fullscreen mode
πŸ’– πŸ’ͺ πŸ™… 🚩
mattpocockuk
Matt Pocock

Posted on May 27, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related