What are Hydration, CSR, and SSR in ReactJS?
Uncover the topics that keep most developers confused for the longest time.
Most developers, including myself, were confused about the difference between CSR and SSR. We couldn’t understand Hydration and its basic principles. However, let me fix all that for you. And trust me, it is easy to understand.
But there’s a requirement to learn Hydration. We must first understand client-side rendering (CSR) and server-side rendering (SSR). The concept of Hydration lies within the problems of CSR.
Client-Side Rendering
CSR is a rendering method that renders the entire application on the client (the user’s browser), including the execution of huge JavaScript files instead of rendering specific pieces of code on the server that do not require user input and others on the client.
When users visit our website, CSR renders an empty HTML document on their browser without any data because that’s how fundamentally React works. If you’ve used React, you would know that every HTML page gets combined into one root file, and that file looks something like this.
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
<script src="/static/js/bundle.js"></script>
</body>
</html>
This empty file gets returned to the client browser when there’s a request. Once the browser locates the bundled JS files in this HTML file, the browser begins executing and parsing that JavaScript code, which contains the HTML DOM elements to fill the empty root div. Till then, the user witnesses a blank page.
The JavaScript code in the <script>
tag divides into chunks of code. These chunks slowly execute once the browser locates the JS code. In CSR, these chunks load together, while SSR loads specific static chunks beforehand for faster execution.
The HTML div gets content to display to the user once the browser fetches the JavaScript code from the server to the client device. Within the initial stage and your source code, this root remains empty.
The browser requires the JavaScript files to load the website because the actual data to show the UI interface with its components to the user is present in them. If the JS file is missing, the HTML file will remain empty.
CSR usually takes a few seconds to render the JavaScript code on the client device. Till the rendering completes, users witness an empty white page. Only a few static components are pre-loaded.
When we keep adding additional components, the rendering becomes slower. And on weak networks, it becomes a huge problem. Most people don’t have fast devices with strong ethernet WiFi.
Once the rendering completes, the user can view the entire webpage as a SPA (Single-Page Application). SPA means that all your content is on a single HTML file.
Now, who wants a blank screen? We want to show something to the user till the browser fetches the JavaScript code with the actual data. However, client-side rendering cannot do that.
Server-side Rendering
Instead of rendering the UI interface on the client device, SSR renders a specific chunk of static code on the server beforehand and ships it to the client till the time-consuming dynamic JavaScript code executes.
It doesn’t execute static code on the client device. Instead, it only runs dynamic content on the client device with event listeners and components that require user input.
It creates a basic layout on the server, sends it to the client, and then transfers the JavaScript code with actual data to replace the temporary one. It is like having someone with the same face as a proxy for a few minutes till the original person swaps them.
We will not ship another HTML file to replace the existing one during the second render. JavaScript will provide the new dynamic DOM. React Hydration process will compare the DOM provided by the JS code through the second render with the first render and replace static placeholders with dynamic content.
NextJS supports SSR, and React implements it using React Server Components. NextJS isn’t an innovation. It is a React-based framework that renders the entire application on the server instead of the client.
The initial state of a SPA is static when using SSR with no event listeners or data from DBs, APIs, etc. Everything is static. The dynamic content gets loaded slowly. But hey! At least we don’t see a white or incomplete page.
It makes the process slightly better for small applications and creates significant advantages for massive applications.
But what the heck is Hydration?
Hydration
SSR sends the static skeleton HTML file compiled on the server with temporary data and static information to the client once the client (user) requests to load the website from the server.
After that, the browser fetches those JavaScript files with actual data, DOM components, and custom code to recompose or repaint the application with the desired dynamic requested information.
The virtual DOM created by SSR to serve as a temporary page gets compared with the actual DOM when JS loads. It compares the previous HTML with the new HTML through the difference in DOM trees.
The DOM structure of the temporary page remains the same as generated by the new DOM but with actual data now. We can demonstrate this through the YouTube website.
The image represents the static temporary page. Once the browser gets the JS code, it executes, rebuilds the application, registers event listeners, and restores app states.
The process between the rendering and comparison of the real DOM with the temporary DOM during the first render is the Hydration process.
Once the rebuilding process is completed, the application enters the “Hydrated” state. This state includes comparing and initialising the new DOM nodes with authentic data. Hydration makes the application fully interactive with dynamic information. It happens at build-time.
YouTube is now hydrated. The original DOM tree from the first render doesn’t get changed. Instead, React combines the original one with the new DOM tree generated after understanding the JavaScript code and adopts the existing DOM.
The rendering occurs two times in SSR, while the same doesn’t happen in CSR because the original data reaches the client on the first try and takes ample time to load it till the user clicks off.
Hydration isn’t perfect
Hydration has its cons. The time between the second render and the first makes a significant difference. During this gap, the user cannot interact with dynamic components requiring factual data from the servers. It is called first interaction/interactivity.
React tries to solve this by using Suspense and Streaming with ranking systems based on what the user wants to interact with. This time gap is called the Uncanny Valley. Hydration manages the gap between CSR and SSR, and this assumed valley.
Even with SSR, the user must wait for the JS to re-load the temporary HTML and bring authentic data while they sit and stare at a default landing page with suspense-based cards. It depends on which route you would like to pick.
Most chunks of websites and applications are static. Hence, these static components get rendered with temporary data on the server way ahead of time. They get built at compile-time by generating the initial HTML file.
During Hydration, React or Next assumes that the DOM structure will match between both renders. During the first render, React builds a mental model of the future DOM and then constructs the future DOM using the JavaScript code in the second render.
The Cereal Example
Most cereal packets and boxes don’t have their expiry date printed during the box manufacturing. Heck, the cereal doesn’t even exist when the box gets manufactured.
Hence, companies only print the standard design on the boxes, including the logo, an illustration, pictures, ingredient information, and a small space for the expiry date.
A machine prints the expiry date on the boxes once the cereal production is completed, and the boxes get filled with them. Those boxes have many empty spaces because they do not have the actual content till production.
In the same way, SSR (or two-pass rendering-based) applications are empty at the beginning. They only have the essential information shown to the user. In our case, this gets displayed through the temporary page with loading cards, buttons, etc.
Once the data and content get fetched from JavaScript, the application starts to get filled with actual information. Then, users can interact with the dynamic content. The empty box gets filled with cereals. Our virtual DOM adapts the data from the real DOM through JavaScript.
Summary
In a nutshell, SSR is the process of rendering a dummy loading page of an application on the server and shipping it to the user before loading the huge JavaScript files containing dynamic data that stop the execution of other files.
Once this sample page gets loaded, the server sends the remaining JavaScript files that consume ample time to execute and allows the browser to begin parsing them while the user witnesses a static page.
Based on the data and code from those JavaScript files, the browser re-renders the entire application with the actual data.
Applications created using React and Next JS are SPA-based. It means that these applications combine into one HTML file. And this root HTML file gets displayed to the user.
The other pages, including the main page, are handled using routes, but the root file holds the content for everything as it is the file that gets hydrated.
Hydration is the process of re-rendering the dummy page with actual data. The root file is only sent once and modified later in the second render.
We hydrate those pages. React has a component called Suspense. This component allows websites to provide a temporary page with the sample UI interface till the browser loads the actual JavaScript.
It allows selective components to get hydrated earlier while de-ranking others. If the user clicks on a specific component, that component gets the priority.