Suspense is all you need

With the release of the Hooks API into React new opportunities arise to eliminate even more boilerplate. The one I want to talk about here is Suspense.

If you don’t know it, you should check out the official page. To describe it shortly, it’s a component, like any other, which takes two props :

  • The Promise of a component to render, once it’s available.
  • A loader component to display until the promise is fulfilled.

The use case most people write about involves the import(...) syntax. But that’s not what I’m after here. I will argue that you should use Suspense instead of useEffect in most cases.

Say you have a user ID and want to fetch the associated username. One such component could look like this :

The problem I see in this code could be described as a hidden dependency. You need the getUsernamecall to work but in the end, you are stuck if it did not. You also make this component impossible to test and reuse elsewhere. The getUsername call cannot be mocked or replaced, the server needs to exist.

In other words: the component has multiple responsibilities (fetching and displaying) and creates a coupling between what is displayed and the server we are talking to.

A simple change would be to make the dependency explicit.

By having the username directly as a prop we remove the coupling between this component and the server and extract one responsibility from the component.

But we still have a problem on our hands. Our prop is a Promise, not just data. This means our component still has to wait until the promise is fulfilled, displaying a loader while it’s not.

This is cumbersome as it leads to the multiplication of undefined checks, which worsen with every call we need. Even worse, it’s hard to switch between loaders as nothing is centralized and code is crammed with boilerplate.

Let’s simplify even further: we just take raw props and remove the Promise part.

Of course, this whole logic didn’t disappear. Here is the call to our component’s last version, with User being our component.

At this point, you may ask yourself why we even bother. It looks exactly the same. Keep in mind that, in real-life conditions, the User component would have internal states, on top of which more complex rendering logic would be built.

Now, however, since we have extracted the fetching part of the component, we can abstract it over and reuse it.

With this very simple wrapper, let’s call it Lazy, here is our new User component call.

At this point, we have a unified way of fetching data for one component to render. But then, do we need to copy/paste this piece of code in all our projects? And what about multiples props? And passing a Component inside a callback is ugly, do we have to?

To all these questions I would say: do you still remember the title of this article? Yes, it’s time we bring in Suspense. Here is our previous component but replacing our own Lazy with the power React offers us.

With Suspense we get a unified way of handling our data fetching, without having to write our own little wrapper for every project. It also lets us think of components as data, but that’s for another article.

Now, last but not least: how do we support multiple async parameters? Can it work with async components (using the imports(...) syntax)? What about both?

We could definitely handle all these cases. If you try you’ll notice things quickly become hard to read. To avoid it, allow me to introduce my Lazy-Props library with an example :

Conclusion

We have once again noticed the importance of separating data fetching and display to have testable and maintainable components. One solution would be to write our own wrapper to handle the data fetching, but React now provide us with one : Suspense. To ease its use in complex cases you can combine it with the Lazy-Props library, but in the end, Suspense is all you need.

Lead Dev && Aspiring Software Craftsman

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store