About React Suspense

published at: Sun Feb 19 2023

Let's go back in time — it's late in 2018 and I am breathlessly watching our sweet boy Danny Abramov outline React's new Suspense component.  There's a lot of shit as an application developer I just don't really understand; talk about time slicing, CPUs, whatever.  But mixed in to the talk there is a promise that resonates with me: with a new thing called Suspense you can control the loading state of a component from within that component itself.  A young Andy Gallagher is blown away by this.  Maybe this would open up a new way for me to organise a React architecture? Maybe no more need to drill loading states into a component from a parent via props and instead localize behavior within the component itself?

Fast forward a bit, say, a half of a decade to present day.  Suspense is still a TODO wrapped around an experimental hook in the example provided by the React docs.  There's a bit of discussion about Suspense every now and then.  Outside of opinionated frameworks (e.g. Next.js), in 2024 there's still just one thing that Suspense is used for: code-splitting.  In an average application, this is (maybe) done once at the router level.

It's a bit of a mess!  So it makes a some sense that opinionated frameworks want to take Suspense, make it theirs, and lock in some users.  I can't necessarily blame them?  If you're trying to get some buy-in for your framework, solving a difficult problem that even the React team can't figure out is probably a good look for you.  The industry seems hellbent on this feature making it to market for reasons so might as well capitalize on it?

Either way, within these frameworks we have Suspense now, and this incarnation of Suspense is generally used to enable SSR with streaming.  This specific understanding of Suspense is now ubiquitous enough that the feature is synonymous with SSR with streaming.  I'm actually somewhat OK with this outcome — like I guess it is better than nothing? But it appears that we have bought into a future where React features are tightly coupled to the implementations of a few specific frameworks.  Accordingly, many developers’ mental models of React will become increasingly specific to a specific implementation of React.

So I wonder: is the juice worth the squeeze?  It feels like Suspense is something that some of us wanted (or rather, had hyped to us) for long enough that we were willing to deal with years of a half baked implementation.  I’ve tried it out, have read the docs, and deployed projects that used Suspense.  I know that the TTFB and TTI is for sure lower, but I don’t feel that this massive increase in both complexity and vendor lock-in is worth it for a lot of projects.  Seriously!  There’s a lot of discussion in the front end space about speeding things up, making UX better, whatever.  But let’s give a little  acknowledgement to the fact that when things become more complicated, they are more prone to being fucked up.

Ultimately, I wonder about a lost future where instead of all this energy being put towards Suspense, just a fraction of the time was spent on a library that could just create an initial UI shell, stream the rest of your React bundle, and then hydrate that initial shell.  Obviously this is not very robust, but it’s weird that I feel like something small like this would both lower the complexity ceiling and solve pretty much everything I would ever really try to do with Suspense.  Seriously!  I’m honestly just not going to need multiple layers of Suspense, nor would I trade off codebase legibility for small performance gains.