jahed.dev

Loading is not a boolean.

In the world of client-side data fetching and other asynchronous workloads, we often see this pattern:

const { loading, error, value } = fetchSomething();

if (loading) {
  return <Spinner />;
}

if (error) {
  return <Alert>{error.message}</Alert>;
}

return <View>{value}</View>;

As both a developer and customer of this application, there's a major flaw: I don't know what the Spinner is doing. It could spin forever and I'd have no idea what's going on. In order to find that out, I'd need to dig into fetchSomething.

Yet, when it comes to errors, we conveniently get an error.message from fetchSomething so we know exactly where it failed; assuming it's properly handled. Why don't we do the same for loading?

if (loading) {
  return <Spinner>{loading.message}</Spinner>;
}

Hurray, now we know why it's loading! It's really that simple. loading is now a Loading object instead of a boolean, we can instatiate it however we prefer. We can go even further and add more details to make it more friendly; just like we can with errors.

Conclusion

In a lot of client-side applications on the web, the loading bar is a complete facade. It pretends to show progress across a boolean state using animations. I've always found it a bit nauseating, like a magician doing the same magic trick you've seen a thousands times while you're waiting in a queue. It's also frustrating when something is clearly stalling. Just like errors, providing information reduces that frustration and helps us better communicate our issues.

I've started using this loading pattern in FrontierNav's last update, which also introduced loading bars. FrontierNav has multiple panes of content, each pane in can fetch data. When a pane does so, it propagates the fetch state to the pane's context which gathers them up. The pane can then show a loading bar along the top with actual progress. Sometimes the loading can take a while, so it's useful to see what the pane is waiting for. I haven't refactored all existing fetches to use a Loading type yet but it's a pattern I'll be using going forward.

Thanks for reading.