React Server Components have reinvented development in Next.JS
You may have heard that there’s a new type of component in React: Server Components and they are about to shake up the way we make React apps. So let’s explore how we can incorporate this innovative feature into our daily lives.
What are React Server Components?
React is well known for its focus on components, which are React’s fundamental building blocks. We are familiar with several component types: Pure Components, Higher-Order Components, Controlled Components, etc. In previous years, we’ve come to understand how they work. But React Server Components(RSC) do things a little differently.
RSC refers to components that exclusively operate on the server side. You might say it looks like a classic server-side rendering(SSR), which is partially correct. Both React Server Components and SSR generate HTML on the server side, but there is a key difference that sets them apart:
- SSR sends raw HTML, and after loading it on the client side, the hydration process converts HTML into interactive React components.
- RSC also transmits raw HTML but without any javascript or hydration.
Let’s look at a simple example:
As you can see, ServerComponent doesn’t exist on the client side, just plain HTML generated by ServerComponent on the server. That’s the main innovation RSC brings. However, in this blog post, I’d like to focus on the pros and cons of RSC instead of writing yet another introduction post about RSC. So if you’d like to learn more about the basics of RSC, please see this nice intro.
React Server Components is just another step
You may be aware of the client-server computation side’s notorious cycle. In ancient history, computers were mainframes, which did all the work, and users needed a terminal to connect to them. From the 1980s to the late 1990s, computers became more affordable and powerful. As a result, many organizations shifted computation away from centralized servers like mainframes and moved it toward rich clients instead.
In the 2000s, web applications matured to the point where they could compete with desktop application software. Therefore, the IT industry again started leaning toward service-oriented architecture.
The same situation has happened in the web application frameworks’ microcosmos. Numerous web frameworks started as classic server-side frameworks — Laravel (PHP), Django (Python), Sprint (Java), or ASP (VBScript), to name a few. Then developers and authors of frameworks started combining Javascript and server-rendered HTML in various ways. For example, the framework ASP.Net Webforms(.NET) used AJAX and JS libraries to imitate desktop apps in browsers.
The outcome was bad. Not only was ASP.NET Webform limited, but it also introduced an added layer of complexity. Regardless, Microsoft persisted in incorporating more client features, culminating in the following problematic code:
You don’t have to understand ASP.NET Webforms to see that this is not the code you want to write. Microsoft ultimately abandoned this approach and released ASP.NET MVC. The new framework required developers again to write Javascript on their own and not to rely on clumsy framework components. The cycle has been restarted.
The team behind React has found itself in a similar situation but in reverse order. React has been a client-side library for many years. However, its authors are now trying to shift some of the renderings to the backend. Unfortunately, this means that the idea of “React is only a client UI library” hit a wall as server rendering needs, in fact, some “server” :). To address this issue, React Core developers have formed a collaboration with NextJS, a widely-used backend framework for React.
As a NextJS fan, I am happy about their decision. However, it introduces yet more complexity, as NextJS has already included its own rendering types. In the next section, we’ll explore how RSC works together with NextJS.
To be clear, you don’t need NextJS to use RSC, but I’d recommend it as NextJS shields you from writing your own router and struggling with React functions like renderToPipeableStream.
Have you noticed that React, being only a library, is the main reason why NextJS has become so popular? The NextJS popularity is just a consequence of the vicious circle called the Client vs. Server computation.
Is RSC just another type of rendering?
NextJS developers can choose between client-side rendering, server-side rendering (SSR), and static site generation or combine them. The combination is really helpful when you need to provide great speed, SEO performance, and friendly UX on one page.
When choosing the proper rendering type, it’s essential to remember that different page parts might have different goals. For example, let’s look at the following boring product page.
Let’s look at the possible reasoning behind using different renderings types:
- The header and footer are static except for the logged user info box. In this case, you can prerender and cache the header and footer.
- The login information is specific to each user, so you can utilize client-side rendering to provide personalized information, indicating whether the user is logged in or not.
- Because the image and description don’t change frequently, it seems like an ideal candidate for using Incremental Static Regeneration.
- If stakeholders view information about stocks as insignificant, you can delay rendering it until after loading the main page. This delay can be achieved using either React Server Components or client-side rendering.
- Since comments are not crucial parts of the page, they can be loaded after a delay. If you’re willing to sacrifice a bit of SEO performance, use client-side rendering with lazy loading to accomplish this.
With similar logic, you can ponder all pages on your website. To help you with this “pondering”, I’ve created an opinionated checklist you can be inspired by:
The client-side rendering(CSR)
- SEO is NOT important.
- Your site is a complex application like “Photoshop in the browser” or any interactive administration dashboard.
- You can defer the first load but keep in mind client-side rendering often hurts performance and UX.
- Use it for a smaller part of the page, like the user info box.
The server-side rendering(SSR)
- SEO is important
- If you must generate the page each time a request is made, then utilize SSR. For instance, you may be required to personalize content, or the page content changes frequently.
The static site generation(SSG)
- SEO is important
- The content of the page is almost static.
- You are comfortable with the potential for a longer build time or a delayed first request for every page — documentation.
- SSG gets tricky when running in a dockerized environment.
The Incremental Static Regeneration (ISR)
- SEO is important
- You have content that changes infrequently but needs to be updated periodically. Plus, it is acceptable for your users to sometimes view outdated information.
- As SSG, you might need to tweak your build process to run your NextJS app in a dockerized environment.
The React server components(RSC)
- SEO is important.
- The application logic is complex and needs to fetch multiple data across various resources.
- You can utilize RSC to enhance page performance on lower-end mobile devices for React components with computation-intensive logic. RSC allows the server to execute complex logic and directly transmit the resulting raw HTML to the browser.
- No client-side interaction is needed!
The last point about missing client-side interaction is essential. With the new RSC approach, we need to reconsider our ways of working with NextJS. The subsequent section presents various concepts regarding how the RSC affects our routine coding tasks.
Impact of React Server Components
Streaming
RSC has been designed to work with streaming protocols like HTTP/2 and server-sent events. When a client requests a page from the server, the server begins rendering and sends the resulting HTML in chunks to the client once they are ready. Consequently, the client can begin rendering the HTML even before the server sends the entire page. The NextJS documentation provides a clear explanation of how streaming operates.
The granularity of data fetching.
The RSC performs better when working with data that is (semi-)normalized. You may recall the emergence of NoSQL databases after 2014. During that time, I came across various tutorials advocating using MongoDB-like databases to build online shops. It usually started like this:
Save the product info, comments, availability, and history prizes in one bulk to get fast read/write access to the data.
While it wasn’t necessarily a poor concept, storing data this way may not be particularly convenient for applications employing RSC. RSC shines in a situation where you can provide data in an asynchronous and prioritizable manner.
Product info in our example needs to be in one resource(a.k.a database table), so it renders at first. Afterward, you can transmit images and prices, with the comment section being the last component to display.
Note: Data fetching might be super complex in your case, so please test and compare performance results before splitting or modifying data in your database.
Interactivity
Up until now, all forms of rendering have included interactivity as a default feature. Yet, this is not the case with RSC. RSC transforms JS components into plain HTML, leading to a paradigm shift. The React community has grown accustomed to having client interactivity “pre-built”. This shift reminds me of the days when I was using jQuery and AJAX to retrieve HTML fragments from a PHP backend and then “inject” them into a webpage. RSC is kind of similar to this old pattern, but it all does during the initial loading of the page.
Memory
Regarding memory usage, RSC outperforms standard React components. React’s virtual DOM, while lightweight and efficient, incurs additional overhead compared to the native DOM. With React Server Components, we only send simple HTML, which browsers can render faster than traditional React components.
Performance
It’s similar to memory. Browsers always parse plain HTML faster than server-rendered HTML with hydration or classic React components on the client side. Particularly, RSC shines in low-end mobile devices and on pages with complex logic.
You can also significantly improve page load performance by not using code exclusive to the server in client components. In other words, you may have a certain logic that relies on a large third-party library that increases the size of the client script bundle. Utilizing this library solely in server components can decrease the total amount of data transferred.
Security risks
RSC offers numerous performance benefits but also comes with substantial security risks. Since RSC is not part of the client bundle, using sensitive data in server components, such as API keys or database connection strings, is generally safe. However, developers may inadvertently change server components to client components which potentially expose sensitive information. NextJS provides a mechanism to detect improper server code use within client components, but developers must still exercise caution. For more information, refer to the server-only package documentation.
Caching
Traditionally, server technologies have been really good at caching, thanks to a variety of tools and methods available. Server-side caching options include HTTP cache, CDN cache, in-memory cache, or even distributed cache like Redis. Backend libraries and hosting providers have widely supported these cache options for a long time.
In contrast, client-side caching options are limited to memory and session/local storage, along with a few less common alternatives. Nothing fancy, if you ask me.
Additionally, NextJS has introduced additional caching methods, such as Segment-level Caching, which caches individual outputs from server components, or Per-request Caching. Per-request Caching enables the deduplication of fetch calls on a per-request basis. Learn more about these experimental caching techniques here.
Long story short, RSC has many to offer in the caching area.
Final thoughts
I strongly believe React Server Components will greatly enhance our work and provide another valuable tool in our arsenal. Let’s welcome the future of streaming HTML and embrace inventive approaches for combining server and client functionality to get well-crafted websites.
We are ACTUM Digital and this piece was written by Marek, Senior Front End Developer of Apollo Division.
If you seek help with your project or initiative, just drop us a line. 🚀