At the end of 2020 the React team shared with us their upcoming feature, called React Server Components. This feature is still in research and development, it should not be used in production yet, but we can play around with it. You can find a talk and a demo shared by them here.
React Server Components are normal React components (with some limitations, i.e. they can not use state or effects), that execute on the server. The main pain points that Server Components try to improve are performance and data fetching.
You might wonder how are these different from Server-Side Rendering (SSR), but actually they are complementary. SSR produces an HTML, but we still need to download all the JavaScript code. Server Components use a different format, which will be then translated to HTML. This format allows to refetch our components. The state of Client Components (regular components) will be preserved on refetch.
About Performance
Almost every React application uses some third-party packages, resulting in increased bundle size and reduced performance. Of course, there are some ways to improve these problems client-side: we can include only part of the packages in our bundles or we can implement the features ourselves instead, but it might be time-consuming.
Server Components allow us to import third-party libraries on the server, without increasing our application’s bundle size. So we can say that Server Components are Zero-Bundle-Size Components. Components that are non-interactive and only render static content could be easily migrated to the server.
About Data Fetching
Another benefit is that Server Components have full access to the backend. We all know that endpoints are not always designed with the UI in mind, and we have to do additional processing on the client. By using Server Components we can move the complexity to the server (but also reduce it by taking advantage of direct backend access), leaving our client-side components cleaner.
We could mention many other benefits, like automatic code splitting, UX improvements, etc., but I recommend you read the RFC for an in-depth explanation. For now, let’s see an example, so we can better understand how these components work.
Before we begin...
Two new concepts will be introduced besides Server Components. Our regular React components will be called Client Components, but nothing changes in how we define them. Some components do not use state, effects or backend resources, they just transform some data, we will call them Shared Components.
As a convention, they will have suffixes that show their type:
- Component.client.js (or .jsx, .tsx) - client component
- Component.server.js - server component
- Component.js - shared component
Shared Components, as the name suggests, can be imported both client and server-side. Server Components can import Server or Client Components, but Client Components can not import Server Components.
How to Migrate Components to the Server?
Let’s say we have a component similar to the one below:
// Article.js
import { fetch } from 'react-fetch';
import { format } from 'date-fns';
import ArticleHeader from './ArticleHeader';
import ArticleDeatails from './ArticleDetails';
export default function Article({ artileId }) => {
const article = fetch(`my-api/articles/${articleId}`);
const postedAt = format(article.created_at, 'mm/dd/yy');
return (
<>
<ArticleHeader postedAt={postedAt} />
<ArticleDetails article={article} />
</>
);
}
We can see it fetches the current article from our API, it transforms the article’s date with the help of a third-party library, then renders two components (header and details). We could move Article to the server, as it does not have any interaction, it only reads some data, transforms it, and renders two other components. We will ignore the other two components now, let’s say we want to keep them on the client. As we know, our server component can still import them. So the only thing we need in this case, is to add the server and client suffixes:
// Article.server.js
import { fetch } from 'react-fetch';
import { format } from 'date-fns';
import ArticleHeader from './ArticleHeader.client';
import ArticleDeatails from './ArticleDetails.client';
export default function Article({ artileId }) => {
const article = fetch(`my-api/articles/${articleId}`);
const postedAt = format(article.created_at, 'mm/dd/yy');
return (
<>
<ArticleHeader postedAt={postedAt} />
<ArticleDetails article={article} />
</>
);
}
Easy, right? Of course, our applications might have more complex components and we need to think about how to better structure them in order to fully enjoy the benefits of Server Components. We can combine Server Components with SSR to have an even better performance. This is a really exciting feature, which could bring many benefits for us, developers, but most importantly for our users.
Thank you for reading this article, I hope I made you curious and you try it out yourself. You can find the official demo here.
Top comments (4)
That was an interesting read and the example gave me a good idea of how the Server Components are gonna be useful.
Thanks for sharing. 👌
Thank you! I am glad it was helpful ☺️
Well curated :)
Thank you :)