On December 21, 2020, just before Christmas, the React team posted a blog and RFC about the React Server Components. On the one hand, they announced their progress on React, on the other hand, they hoped to draw feedback from the industry. What is React Server Components? What are the highlights?

Front end of a brief history of

  • [Static] In the beginning there was no front end or back end at all. At that time, I used Dreamweaver to write static HTML pages and then deployed them to IIS (Internet Information Services) on a computer. When the page is requested, the HTML file is returned.
  • Later on, the server side becomes a bit more complex and HTML pages start to be written using various templates, such as The Java family FreeMarker, ASP, PHP, etc. Back then, back end development was integrated, and at most template writing was the original front-end domain, but back then, it was often done by today’s back end development.
  • This all changed in 2005 with the advent of Ajax (Asynchronous JavaScript and XML). JS scripts can request data from the server independently, and then process and update the web page. In this process, the back end is only responsible for providing data, and the front end does other things. It was literally the first year of Web development technology. The Web has moved from 1.0 to 2.0. It promotes separation of the front and rear ends.
  • [MVC] The front end can get data through Ajax, so there is a need to process data, so it prompted the birth of the front MVC. Later in this phase, the front end gradually began to have a bit of engineering shadow, and began to be influenced by CommonJS, the concept of modular programming, the corresponding CMD and AMD specifications were born. There was the build tool Grunt/Gulp, and there was the specification JsLint for coding.
  • [MVVM] MVVM is also a software architecture pattern, which is evolved on the basis of MVC, removing the Controller in MVC and increasing the two-way binding of data. The most representative framework is Angular from Google, which is an enhancement of THE HTML language and the core concept is two-way data binding.
  • 【SPA】 The first time a user initiates a page request, the back end returns HTML, CSS, and JS files. JS file includes the processing of page switching logic, which is the key to the realization of single-page application. It uses Hash or History technology to realize that when switching pages, it first obtains the data required by the new page through Ajax, and then JS switches to the website according to the site to be switched. Use the obtained data to stitch together the HTML for the page to be displayed. The whole action of switching pages is completed by the front end. This is a single-page application, where all resources are loaded only on the first page request, followed by an Ajax request for data.
  • 【SSR】SPA turns the Web into an application form, which is client side render. Client-side rendering has its drawbacks, such as not doing SEO(Search Engine Optimization), because all JS and CSS will be loaded at the first visit, and HTML is assembled in the front end, it is bound to lead to the first screen loading and rendering time will increase, Impact the user experience (although with code splitting, SPA is still the most popular solution as long as SEO is not required). At present NextJS is a good SSR framework. In addition, UMI also supports SSR and automatically downgrade to CSR when SSR fails.

background

Good & Cheap & Fast

At the beginning of the video, Dan mentioned the concept of Project Management: In a Project, it is difficult to have the three attributes of Good, Cheap and Fast at the same time, and usually only the two can be pursued. The same applies to React development: good user experience, low cost code maintenance, fast performance.Take an example: a typical example of a presentation component. Give a composer ID and render his details page, where you can see his TopTracks, Discography. Of course, TopTracks and Discography do not have to be available on the details page (references can be made elsewhere, hopefully public, not private components of the details page).

Good user experience, fast performance

If you can uniformly fetch data from the parent component and pass it to the child component, performance is fast and multiple API requests are avoided. User experience is good. However, maintenance costs are high. Each data has to be passed layer by layer. If the API is changed, each sub-component has to be changed. In addition, reusing TopTracks and Discography requires rewriting the logic for retrieving the data elsewhere.

Fast performance, low cost code maintenance

If we only allow users to see TopTracks and Discography on the details page, then these components don’t have to be common and we can render them cheaply and quickly. However, the user must go to the details page to see these components, and the user experience is not good.

Low cost code maintenance, good user experience

We put each data capture logic in its own component, which is easy to maintain and a good user experience. But the performance is poor, 3 requests are sent, and these requests are “waterfall flow” : Render ArtistDetails first, wait for it to get the data, then continue rendering children, and children will start getting the data.

This is just one example of a front-end project, but it’s quite common. (Although they may occur for different reasons, in many projects the API requested by the latter depends on the result of the former. The above example is simply a waterfall flow due to the order of rendering.

Existing solutions

The existing problems are mainly the data acquisition logic between Client and Server, which comes and goes again and again, resulting in a waterfall flow that consumes a lot of time. GraphQL solves this problem by requesting the data all at once and getting it all. GraphQL + Relay (React library for GraphQL to fetch data) this brings a lot of benefits internally at Facebook, but is difficult to popularize:

  • GraphQL is not universal, not everyone can use it
  • It is too expensive to transform existing huge projects into GraphQL (” We have to transform the back end when it is a front-end pain point to solve “)
  • Not everyone likes it

New solutions

The React team’s new solution looks like this:

The Client sends the request, and the Server directly renders the component and obtains data locally on the Server. No matter how long the waterfall is, all the data can be quickly retrieved, and then renders the component on the Server and returns it to the Client in one go. The React Component running on the Server is the React Server Component. In the past, the front end was the Client Component:

Now, after introducing the Server Component, the Component tree might look like this:

React Server Component

See demo: github.com/reactjs/ser…

To get the data

NoteList.server.js

import {fetch} from 'react-fetch';

export default function NoteList({searchText}) {
  const notes = fetch('http://localhost:4000/notes').json();

  return notes.length > 0 ? (
    <ul className="notes-list">
      {notes.map((note) => (
        <li key={note.id}>
          <SidebarNote note={note} />
        </li>
      ))}
    </ul>
  ) : (
    <div className="notes-empty">
      {searchText
        ? `Couldn't find any notes titled "${searchText}".`
        : 'No notes created yet!'}{' '}
    </div>
  );
}
Copy the code

The Server Component can fetch data directly (it does not need to be useEffect like the Client Component). It can also manipulate local files and even execute database queries directly. The Server Component executes on the Server and does almost everything the back end can do.

Referencing other components

The Server Component can reference the Client Component. It is returned to the Client as an instruction. The Server Component serializes the Component and the data it receives from the IO request into specific data structures (called directives) that are passed to the front end as streams:

The client directly fetches the stream populated with data at run time and performs streaming rendering with Concurrent Mode. Instruction meaning:

  • M: Download the Client component. The module will be downloaded immediately after receiving it
  • J: Serialized Server component that can be rendered directly upon receipt
  • Suspense S: Symbol, Suspense is one of them

Dependencies of server-side components are not packaged

Date-fns is referenced in note.server. js, but not in Sources. And none of the Server Components are in there. Amazing!

The constraint

Server Component cannot have stateful, event listeners. If interaction is required, only the Client Component can be used. (See sideBarnote.js, which passes “data” (actually JSX) to the Client Component, The Server Component cannot pass function parameters to the Client Component because functions cannot be serialized. And JSX is serializable, so you can also pass JSX. If the JSX passed is also a Server Component, it will be rendered by the Server before being sent to the Client. (This means that the Server Component will not be downloaded by the Client.)

Keep the state of the Client Component while mixing

The list on the left is a Server Component. The reference Client Component keeps the expanded/folded state. If you add or remove items, their expanded/folded state is kept! Amazing! In the ERA of CSR, this is a function that costs some money to implement. In the Server Component, re-render can keep the status of the Client Component.

Shared Component components

If a component ends in.js instead of.server.js or.client.js, it can be rendered on both server and Client. If Shared or Server Components are used in the Server Component, they will be rendered by the Server and returned to the Client as directives. They will not be downloaded to the Client. If Shared or Client Components are used in the Client Component, they will be rendered in the browser and downloaded to the Client. If the Client Component uses the Server Component, it sends the request. Amazing! Many systems are multi-character, and different characters should see different things. This component-level on-demand loading is exactly what we want!

This is a very common React code pattern these days. However, by switching it to a Server Component, the EditToolbar Component will not be downloaded by anyone without editing permission. (CSR mode can only be downloaded but not displayed)

Change + update, only trigger 1 request

In the CSR era, we used to call apis to modify data before getting new data. But with the Server Component, we only need one request to do this! Amazing!

React IO

React encourages the community to develop and maintain these IO libraries for use with Server Components. This does not mean reinventing the wheel, however, they are simply a thin wrapper around existing node libraries, such as react-fs which only encapsulates FS and react-fetch which only encapsulates FETCH. Less than a hundred lines. The React IO library just adds a caching layer.

About Slow Requests

Suspense, rendering in the form of flow, low development cost, good effect!

Will it replace GraphQL

No, they can work together.

advantage

Solve waterfall flow problems

0 packing volume

Suppose we develop an MD editor. The server passes a string in the MD format to the front end. We need to introduce a library on the front end to parse MD into AN HTML string. This library has 206K. import marked from ‘marked’; // 35.9k (11.2k gzipped) import sanitizeHtml from ‘sanitize-html’; / / 206 K (gzipped 63.3 K)

function NoteWithMarkdown({text}) { const html = sanitizeHtml(marked(text)); return (/* render */); }

How do we solve this problem with ServerComponent? Simply mark NoteWithMarkdown as ServerComponent and put the logic to import and parse MD on the server side. ServerComponent does not increase the front-end project packaging volume. In this case, we reduced the front-end 206K (63.3K gzipped) packing volume and MD parsing time at one time.

Automatic code segmentation

Dynamic import of components can be implemented using react. lazy. Previously, this had to be done manually when we switched components/routes. In ServerComponent, this is all done automatically.

In the figure above, the list on the left is ServerComponent, whose data is dynamically loaded when a card is clicked.

Contrast with related technologies

SSR

Compared to SSR in the past, you will not lose the state of the client after pulling; When SSR is first accessed and returns the rendered page, Server Components outputs a series of instructions. Server Components can be loaded in chunks and reduced packaging volume to further improve the loading speed. Note: The two are different technical solutions to solve different problems, but can be mixed. The main problem SSR solved was SEO and first screen rendering speed.

Backend frameworks such as PHP

In the PHP/ASP era, pages were rendered by the server. Upon receiving the request, the server queries the database, “stuffs” the data into the page, and sends the generated HTML to the client. When the user clicks the link, repeat the above steps. This is not a good user experience, almost every operation requires a page refresh, and the server returns to a new page after processing it.

SPA

Angular/Vue/React single-page apps (SPA) are client-side renders. When the server receives the request, it sends index.html and js/ CSS /img to the browser, which renders the entire page. Subsequent user operations are the same as before with PHP /jquery, with ajax and back-end interactions. However, compared to PHP, the first visit only returns idnex.html empty page with no content, can not do SEO. The other thing is that the page doesn’t display until the JS/CSS and interface are returned, and the first time you visit it, you’ll get a blank screen.

Recommended reading

  • Reactjs.org/blog/2020/1…
  • Github.com/reactjs/rfc…