DEV Community

yahyanaim
yahyanaim

Posted on

Bridging the Gap: Exploring the Power of Hydration in Web Development

Image description

Hydration refers to the process of attaching JavaScript behavior to HTML elements that have been rendered on the server. It is an important step in making a web page interactive and dynamic.

What's the problem that Hydration solve?

When a web page is initially rendered on the server, it is in a static HTML form. This means that the content is pre-rendered and lacks interactivity.

to provide a dynamic and interactive user experience, JavaScript frameworks and libraries are used on the client-side .

These frameworks attach event listeners to HTML elements and update component states, allowing for interactivity.

Hydration addresses the problem of reconciling the static server-rendered HTML with the dynamic behavior on the client-side.

It ensures that the interactive features and functionality of the web application are seamlessly applied to the server-rendered content without losing any previously rendered content or state.

Hydration in Practice:

Lazy-loading the JavaScript: Progressive Hydration ?!

The lazy-loading is refer to a technique used to optimize the loading and execution of JavaScript code. It involves delaying the loading of JavaScript files until they are actually needed, rather than loading them all at once during the initial page load.

Image description

Progressive hydration takes the concept of lazy-loading a step further by selectively hydrating specific JavaScript functionality as it becomes necessary.

Instead of hydrating the entire JavaScript codebase, only the components or features that the user interacts with are hydrated.

Here's an exemple to unserstand what is the lazy-loading :

Image description

In this example, we have a placeholder element (<div id="lazy-component-placeholder"></div>) that serves as a marker for the component that will be lazily loaded. Initially, only the placeholder element is rendered on the page.

When the placeholder element enters the viewport (10% of it becomes visible), the Intersection Observer triggers the handleIntersection callback.

Inside the callback, we stop observing the element, and then we dynamically create a <script> element and set its src attribute to the JavaScript file containing the lazy-loaded component. Finally, we append the <script> element to the <body> to load the JavaScript file.

By using this approach, the JavaScript file for the lazy-loaded component is only fetched and executed when it is actually needed, improving the initial page load time and overall performance.

Islands: Partial Hydration

A web page as mostly static HTML that doesn't need to be re-rendered or hydrated in the browser. Inside it there are a few places where a user can interact which we can refer to as our "Islands".

This approach called "Partial Hydration" since we only need to hydrate those islands and can skip sending the JavaScript for anything else on the page.

Image description

With islands, the web page is divided into independent sections or components, each responsible for its own hydration.

These sections, also referred to as islands, can be separate modules, widgets, or even entire sections of the page. Each island can have its own JavaScript dependencies, state management, and interactivity.

To undersatnd this approche here's an exemple :

Image description

In this example, we have a parent component (ParentComponent) that includes an island component, When the user clicks the "Show Island" button, the state isIslandVisible is set to true, and the island component is rendered.

The island component is a simple

element with a heading (<h2>) and some content (<p>).

By conditionally rendering the island component based on the isIslandVisible state, we achieve the selective hydration of the island component.

The island component is only hydrated and rendered when the user triggers it by clicking the button.

Out of Order Hydration ?!

Imagine you're developing a social media application with a feed of posts. Each post on the feed contains various components, such as the user avatar, username, post content, and comments. When a user opens the feed, they should be able to see and interact with the posts as quickly as possible.

In the hydration approach, the entire feed would be hydrated in the order it appears in the HTML structure. This means that the user would have to wait for the entire feed to be hydrated before they can start scrolling, liking posts, or leaving comments.

With out of order hydration, you can prioritize the hydration of the posts that are currently visible in the user's viewport, allowing them to immediately interact with those posts while the remaining posts are hydrated in the background.

Image description

Explaination :

The Feed component fetches the feed data from an API and renders multiple Post components based on that data.

With out of order hydration, you can modify the rendering logic in the Feed component to prioritize the hydration of posts visible in the user's viewport.

This can be achieved using techniques like code-splitting or virtualization libraries such as react-window or react-virtualized.

By prioritizing the hydration of visible posts, the initial rendering and interactivity of the feed can be significantly improved. The user will be able to scroll, like posts, and leave comments on the visible posts while the remaining posts are hydrated in the background.

As the user scrolls down the feed, additional posts outside the initial viewport can be lazily loaded and hydrated as they come into view, further optimizing the performance and resource usage of the application.

Server Components

In Server Components, component logic such as data fetching and database mutations is executed exclusively on the server. This proximity to the data source eliminates unnecessary client-server round trips, letting your app simultaneously fetch data and pre-render your components on the server.

here's an exemple :

Image description

Here, we are able to asynchronously fetch data from an external source and pre-render the content entirely on the server. The generated HTML template is then seamlessly streamed into the client-side React tree. Server Components can also import Client Components as seen with the AddPostButton import above.

Using Server Components offers many performance benefits because they never re-render, resulting in faster page loading times. Unlike in rendering techniques like SSR and SSG, the HTML generated by RSCs is not hydrated on the server and no JS is shipped to the client. This significantly increases page load time and reduces the total JavaScript bundle size.

Conclusion:

The field of optimizing SPA is constantly evolving, with new techniques emerging regularly. The truth is, the best solution often involves combining different approaches.

Imagine a scenario where we have a compiler that generates sub-component islands, supports lazy loading and code-splitting, incorporates out of order hydration, and includes server components for server-side rendering. This combination could offer significant benefits.

On one hand, this approach could greatly improve performance, reduce payload size, and enhance interactivity. The compiler would enable efficient code-splitting and lazy loading, while out of order hydration would prioritize critical components. Server components would further optimize performance by rendering on the server.

In conclusion, while the ideal solution varies depending on project requirements, ongoing research and development aim to provide more efficient and user-friendly web experiences.

This revised version maintains the key points while reducing the length and simplifying the language.

Top comments (0)