Written By Manu Mtz.-Almeida
Back in 2022, during a disastrous conference, I had a good chance to talk with friends from Solid and Astro — it was the best part of the conference! There was a healthy exchange and challenge of ideas from all sides.
“Resumability is just hydration.”
— Those dawgs challenged me.
I had a strong intuition they were wrong, but how could I make my point? Which mental model could help show the difference?
Does jQuery hydrate?
Let’s go to the basics. What do we define as hydration in the first place? At some point during our conversation, things turned sideways and anything could be called hydration, even a little jQuery script of your Ruby on Rails app.
“If running any Javascript means hydration, then hydration as concept loses all meaning. It’s not useful and an attempt to rewrite history”
Hydration as an algorithm is first seen when SPA frameworks like React, Vue, Svelte, or Angular added SSR support. For those frameworks to become interactive in the browser, they had to re-execute the whole app from the root (<App/>
) to recover the state and event handlers that got lost when serialising to HTML (renderToString
).
All hydration implementations take a single component as root (usually <App/>
), and for this to become interactive, every component in the tree must execute. Only after the event handlers are set up, can a user interact with it.
Hydration can only be understood through the process of adding interactivity to a tree of components that previously executed in the server. It’s a O(n) algorithm where N is the number of components to wake-up.
Partial hydration
The concept of partial hydration, brought to prominence by the Astro framework, emerges from the understanding that not all parts of the tree need to be hydrated, particularly those that are entirely static. This approach establishes 'islands of interactivity', reducing the workload on the browser, which leads to quicker interactivity.
Partial hydration is exactly that: calling hydrateRoot()
multiple times at different moments, so the name fits well.
However, it's essential to highlight that these 'interactivity islands' need to be manually created by developers. Also, these islands create boundaries, implying each island operates as an independent sub-application, which might hinder communication between different parts of your application.
React Server Component is hydration
Just like partial hydration, RSC is hydration with a different last name, something we could call Sparse Hydration.
Instead of creating isolated islands, RSC maintains a single root, allowing components to communicate with one another. However, the “Server Components” from the root doesn’t need to re-execute in the browser. Instead, React serializes the vNodes of those components into the HTML as data. It’s a space-time trade-off.
Just like with the island architecture, developers must put in the effort to set boundaries in React Server Components, using 'use server' or 'use client' directives.
Resumability is fundamentally a different algorithm
Finally, we delve into resumability, a paradigm that advocates instant interactivity without the need for hydration or walking up components. It departs from the tree structure entirely.
Resumability is unique in that the roots (or entry points) are the event handlers, not the components.
In traditional hydration, partial hydration, and React Server Components, the components act as the roots. For partial hydration, you might have several roots, while for React Server Components, you have a single one.
Resumability, on the other hand, places event handlers at the root. The arrows point from the events back to the components, indicating no need to run any user code, even for components that can re-render. This approach effectively treats all components as static, regardless of whether they are or not.
Resumability is the hash-map of frontend development, a O(1) architecture where it does not matter how many components your application has, the amount of JS in constant. Hydration is fundamentally a tree walking, that requires the download and execution of all interactive components.
Conclusion
Different shapes of hydration have various advantages and disadvantages (which deserve a separate blog post). Fundamentally, they run the same algorithm, allowing developers to make different trade-offs that alter the 'N' of the equivalent O(N) algorithm.
Partial hydration allows developers to split their application “vertically” into islands, while RSC allows developers to split applications “horizontally.” In addition, RSC with suspense boundaries can implement lazy hydration of subtrees within the app.
On the other hand, the topography of Resumability makes it a completely different algorithm — similar to the idea that you cannot turn a ball into a donut without breaking it. Hydration-based frameworks cannot become resumable without breaking some plates.
For a topologist, a sphere is the same as a cube: they are both three-dimensional shapes without any holes.