DEV Community

Cover image for How Suspense works in React18
gursidak_singh
gursidak_singh

Posted on

How Suspense works in React18

React is one of the trending and most popular client-side libraries for developing painless interactive UIs. Already it has its roots deep in the market, but obviously, the goal is to achieve the best UI experience but not better. So React comes up with another major feature in its Version 18 that makes the User Experience faster and more interactive, which can be termed as "Non-Blocking User Experience". The term itself defines its meaning enough. That there's something that's gonna remove all the obstacles that make it slow while loading and interacting with any react app.

So Let's Dig Deep into the underlying concept to understand well the working of these features that makes it lighting fast.

Majorly there are two ways to use React

  • Client-Side Rendered App

  • Server Side Rendered App

Let's Start our Discussion on Problems with These two, that react 18 solves

Client-Side Rendering

Image description

In the above image all the stages of providing a view to the user, when he requests a page on react app is shown

It can be seen clearly that after the user request a page, the very first step that is performed is to LoadJs, then it fetches the data required for the views, and finally, it renders the components by the process of hydration (the process of making webpage interactive by connecting each DOM components with its respective logic).
Now the problem here can be seen clearly that until the process of hydration is not completed the user sees a blank white screen, which is a very bad user experience, and if there is some component that has large bulky Js with it to compile and render view, It makes it weirder. Also in case of a slow internet connection, it takes a lot of time to load the script and render an interactive view and until the script is loaded what the user sees is a blank screen.

Now the question that arises in mind is that we already have a solution for this problem and that is to render pages from the server-side

So, Let's discuss that case as well

Server-Side Rendering

Now what will happen in server-side rendering is, It will not resolve the problem of large javascript bundle or script also not of low internet speed, but it acts as an additional layer of optimisation over a client-side rendered app by providing pre-rendered HTML/CSS pages that prevent the browser from showing the blank screen, although these pages are not interactive until the process of hydration is done. But still, a better user experience than Client-sider rendered web app.

A typical app uses server-side rendering works in this way.

Image description

When a browser receives a request for a page, On the server it fetches data for the entire web page, also on the server, all components are rendered as HTML/CSS. Now this HTML is sent to the browser and browser hence rendered in the browser.

Clearly, for large and heavy web apps server-side rendering is very useful, instead of rendering the blank page to the user, the browser shows HTML/CSS rendered page and till the time user is getting the HTML/CSS of the page browser hydrates it to make it interactive.

Now the problem of a blank page is solved to much extent, but not completely as server rendering renders an HTML/CSS-based view to the user but it's not interactive.
Consider the case you go to the browser and request "https://youtube.com" and you get a server-side rendered HTML/CSS but until the hydration of large bulky JS is not completed or consider you have a slow internet connection, the page will not become interactive till then, buttons will not be clicked, videos will not be played, and that will make it useless even its showing view to the user. We need javascript to make it interactive

Now, this is server-side rendering explained in four steps :

  1. We fetch the data on the server for entire application
  2. We Render the code into HTML for entire application
  3. We Load the Js on the browser for entire application
  4. We hydrate the components to make the app interactive, for entire application

Yes, we do every step for entire application and simultaneously in server-side rendering. At every stage whole application is processed at once(in one pass).

Let's understand it well with an example - Suppose we have an app that has the following components as shown in the image below

Demo Project Structure containing different components

We have Navbar, Sidebar, Posts, and Comments components.
Now suppose we have component that has heavy Js and large expensive API requests for a large amount of data. We can say it's a troublemaker part of the application. Now, this component will make trouble at every stage, Also we can't skip this component as without posts component application will be useless.

The main problems can be

  1. Problem 1 - Fetch Everything, before you can Show Anything
    Now as discussed above in server-side rendering how server fetches data of all application and renders it into HTML pages and provide a browser to show it to the user, but code can't be sent for rendering until all the data is fetched and remember Posts component involved heavy and large API requests. Now it will put us back into the same situation where the user will see a blank page until pre-rendering is done and the browser receives a static view to render.

  2. Problem 2 - Load Everything, before you can Hydrate anything
    This means we need to load the JS of the entire application before we can hydrate anything. Now again Posts is the component with heavy Js

    We can see every component has been Loaded except the component, which is still loading its Js.
    Now again in pre-18 versions of reacting the app will wait for hydration until all the components have loaded their JS.

  3. Problem 3 - Hydrate Everything, before you can Interact with anything
    Again the user will not be able to interact with any component until the code gets hydrated, for example, if the user will click on the profile component it will not be opened as there is no event- listeners and logic attached to components(hydration not done yet, due to large javascript connected with Posts component, the whole process gets late).

Hence In all 3 problems discussed above, there is something very common that's making delays in each step. So here the react 18 comes into the picture with its amazing feature "Suspense", which solves this problem. Rather than each stage of needs to happen for all the apps in one pass at one time, suspense allows us to break our work into multiple parts.

Image description

As shown above, wrapping a component in suspense allows us to show another component (passed in fallback), until the actual component is loading and hence resolves the problem of carrying out each step in one pass and that too without facing any delay.
Now the react will keep processing that component in the background and shows another component for example a spinner as a placeholder for that component.

Image description

Hence the initial page render happens sooner, there is no blocking in any stage. The loader provides the user an indicator that something is here that is going to load soon, instead of a blank screen that makes a really bad user experience. Now once the posts are fetched, rendered, loaded, and hydrated they are rendered at that particular place

Now with this, all the above problems are resolved,

In the first step, there is no blocking in fetching data due to expensive API requests, once the data fetching of all components, other than those wrapped in is completed the code is sent for the next stage, and the data fetching for suspense components keep on happening asynchronously behind
Hence we need not Fetch Everything before you can Show Anything.

Now after rendering the code as HTML, sent to the browser for loading Js, now again if no bulky Js are blocking the loading stage send the code to the next stage without any delay.
Hence we need not Load Everything before you can Hydrate anything

In the last stage, all the other components get hydrated except the one with troublemaker behaviour, in place of it the placeholder component provided in the fallback property of suspense is loaded and hydrated. Now all the components are interactive and the user can interact with any components, instead of the fact that posts are still loading. For example, a user can click on a profile and open the profile page, though the posts are loading.
Hence we need not Hydrate Everything before you can Interact with anything

This is all about React 18. So let's make our apps lightning fast with the great new feature.

Discussion (8)

Collapse
vkostunica profile image
vkostunica • Edited on

Why there is no practical code example or even better example repo or Codesandbox? In theory all works beautiful but in reality you get bunch of hydration errors whenever server and client states mismatch, and there is no way to debug it because everything happens in fraction of a second on page refresh and error logs dont point to specific component.

Do you have same practical examples with Next.js?

i.postimg.cc/Ssd5qhkt/image.png

Collapse
sidak profile image
gursidak_singh Author

I will share a practical usage of it very soon. But in this post, my goal was to explain how this feature will bring a great change, the way react apps respond on load

Collapse
andrewbaisden profile image
Andrew Baisden

This is an excellent article Suspense has changed how I work in React when fetching data.

Collapse
sidak profile image
gursidak_singh Author
Collapse
shivam_jha_828c7a03f00815 profile image
Shivam Jha

Awesome post

Collapse
sidak profile image
gursidak_singh Author

Thanks

Collapse
simaraneja profile image
Simar Aneja

Very well written.. 👍

Collapse
sidak profile image
gursidak_singh Author

Thanks ❤️