Why React Server Component (RSC)?
Simple Concept
- Client Component : UI = f(state)
- Server Component: UI = f(data)
- Combined: UI = f(data)(state) but not UI = f(state, data)
- The UI is updated using
Curryingwith f(data)(state), while f(state,data) is a regular function call. This means that f(data) occurs on the server, but f(state) occurs on the client. Please keep in mind that there are some differences between f(data)(state) and f(state, data).
Long story Short version
tldr:
Before RSC coming, React was always treated as a SPA library/framework(ecosystem/architecture) because SSR for React was invented by Vercel, the author of Next.js.
RSC is an additional layer in traditional React for client components, and it's the first time React has introduced server-side matter.
Before RSC, you can consider that React will be packaged as a JS bundle and sent to the browser for download. At this point, it is similar to downloading a mobile application from an app store.
After downloading the bundle in the browser, all JS programs are installed in browser and any subsequent fetch or navigation will be done on the client side. For meta frameworks like Next.js and Remix, they won't include all of your ReactJS program into one JS bundle; instead, it will be divided by route/segment.
So SSR generates HTML on the server-side and sends the corresponding JS bundles for hydration in the browser to add interaction. This is different from RSC, because SSR naturally requires hydration in the browser even if it's server-side rendered HTML. The HTML generated in server is the real DOM, but the virtual DOM has not been generated yet. Therefore, in the browser, the component needs to run one more time to generate the virtual DOM and fiber tree. Otherwise, React will lose state(hooks) for the client component and reconcile will not be able work. This is why SSR runs twice - once on the server and once on the client.
After the introduction of RSC, a new data format called RSC payload will be used to represent components in React. There will be no browser API or hook involved; instead, a binary or JSON-like payload will be utilized within the browser by reactjs. The reason for not using HTML to represent RSC is due to its lack of flexibility in reusing and placing components correctly when React needs to re-reconcile them in rerendering phase.
History
From SPA (Single Page Application) to SSR (Server-Side Rendering), and now RSC (React Server Component), ReactJS has evolved over the past 10 years.
I remember the first time I used ReactJS when it was still using class components. Now, we have the option to define components using functions with hooks.
SPA is not good for user experience or SEO.
SSR does not effectively reduce the JS bundle size to improve performance.
RSC was introduced to solve this problem. Although it is not free, the JS bundle becomes an RSC payload, making it worth learning and using.
React Server Component is a new concept. They add a new layer to React client components,
It's similar to server-side rendering where the HTML is generated on the server, but RSC generates React-like JSON format.
AS Dan explained.
The component's location of import determines whether it becomes a server or client component.
RSCs do not require hydration, meaning the JS bundle is smaller than when using SSR (server-side rendering).
On the server(here is using NextJS as example), RSC generates a binary payload in React JSON format and send it to the browser. The browser then uses this with the hydrated client component to render the UI.
It is not meant to be used as a replacement for SSRs, but rather as a complement to them.
Some thoughts
Here is my summary:
- The first layer is the server component and the client component
- The client component is traditional reactJS component that can be rendered either on the server side (SSR) or on the client side (CSR). With SSR, both HTML and JS bundles are generated on the server and sent to the client for hydration. On the other hand, with CSR, only the JS bundle and Shellnut HTML are sent to the client for rendering.
- The server component is officially released on reactjs18 and nextjs13, so all the component before nextjs13 and reactjs18 is client component. server component is a non-interactive component compared to client component, it can use server API or access server system.
- In the Server Environment
- React renders Server Components into a special data format called the React Server Component Payload (RSC Payload).
- Next.js uses the RSC Payload and Client Component JavaScript instructions to render HTML on the server.
- In the Client Enviroment(browser)
- The HTML is used to immediately show a fast non-interactive initial preview of the route.
- The React Server Components Payload is used to reconcile the Client and Server Component trees, and update the DOM.
- The JavaScript instructions are used to hydrate Client Components and make their UI interactive.
- The RSC Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The RSC Payload contains:
- The rendered result of Server Components
- Placeholders for where Client Components should be rendered and references to their JavaScript files
- Any props passed from a Server Component to a Client Component
- On subsequent navigations, Client Components are rendered entirely on the client, without the server-rendered HTML. This means the Client Component JavaScript bundle is downloaded and parsed. Once the bundle is ready, React will use the RSC Payload to reconcile the Client and Server Component trees, and update the DOM.
- Server component is rendered on the server side and sends the JSON notation(using streaming which means the component is async to send) used to render HTML instead of sending the whole HTML to the client (except for the initial load, it is sending the HTML in Nextjs)
- ReactJS will generate the RSC payload for RSC.
- NextJS will use generated RSC payload with client component JS instructions to render HTML on the server for the initial load. which means, client component and server component both are used in SSRd when user refresh the browser or first time visit the website.
- After the initial load, the JS bundle(most part, like layout, hook) has been downloaded in the user browser, so the subsequent request/navigation, RSC payload will generate in server too and send to client to rendering the page.
- At this moment, the existing JS bundle may lack of some elements for ongoing client component, so server will send the remind JS bundle to client for reconcile react tree and update the DOM.
- In the Server Environment
- you can not import server components into the client components as this approach would require an additional server round trip.
- but you can composite it in another server component
- also you can use Passing Server Components to Client Components as Props
- Instead, when designing Client Components you can use React props to mark "holes" for Server Components.
- The Server Component will be rendered on the server, and when the Client Component is rendered on the client, the "hole" will be filled in with the rendered result of the Server Component.
- A common pattern is to use the React children prop to create the "hole". We can refactor
to accept a generic children prop and move the import and explicit nesting of up to a parent component.
- The second layer is CSR and SSR
- As mentioned above, CSR sends the JS bundle to the client and ensures that rendering occurs on the client side.
- SSRd is pre-rendered at the request or build time and caches their HTML and JSON on the server, which is then sent to the client for hydration by ReactJS.
- However, the SSRd or CSRd will have a large amount of JS bundle for hydration. Slow performance of the network boundaries.
- the difference between RSC and SSR
- The RSC is a new thing that is added to the existing react tree as a new layer like the below pic
- By utilizing RSC, we can prevent the need to send the entire JS bundle to the client's browser. This is because RSC's library is only used on the server-side. As a result, this leads to a smaller JS bundle size.
In contrast, for SSR, HTML is rendered either during build time or request time (similar to RSC). However, in order for hydration to occur, all of the JS bundles must be sent to the browser.
Since RSC does not have interactive functionality, its JS bundle size remains smaller than that of SSR. - The client component can also be SSR, just like before because the client component has interactive functionality, hydration is needed, the JS bundle will be bigger.
- The RSC operatesasynchronouslyand usesstreamingto send progressively updated results to the client, resulting in faster loading speeds.
- reduce the waterfall requests
React Server typically runs either at the build time (default), or on an actual server. React Client typically runs in both environments (in the browser it manages the DOM, in other environments it generates initial HTML).- For the initial load, the RSC will provide the react elements along with the JS bundle, but client component can also be SSRd, so the HTML will be generated and sent from server in nextJS for initial load. Subsequently, when navigating to other pages or interacting with the website, a React-style JSON response will be sent to stream to the browser for rendering of the UI.
- tl:dr -
- No, they’re complementary. SSR is primarily a technique to quickly display a non-interactive version of client components. You still need to pay the cost of downloading, parsing, and executing those Client Components after the initial HTML is loaded.
- You can combine Server Components and SSR, where Server Components render first, with Client Components rendering into HTML for fast non-interactive display while they are hydrated. When combined in this way you still get fast startup, but you also dramatically reduce the amount of JS that needs to be downloaded on the client.
- The third layer is Static and Dynamic rendering
- By default, Next.js 13 uses static rendering, which generates all components ahead of time during the build process.
- With Static Rendering, both Server and Client Components can be prerendered on the server at build time.
- The result of the work is cached and reused on subsequent requests. The cached result can also be revalidated.
- This is equivalent to Static Site Generation (SSG) and Incremental Static Regeneration (ISR) in the Pages Router.
- the dynamic rendering also renders the page in the server but will be rendered every single request
- With Dynamic Rendering, both Server and Client Components are rendered on the server at request time. The result of the work is not cached.
- This is equivalent to Server-Side Rendering (getServerSideProps()) in the Pages Router.
- we use two dimensions to identify whether the component is using static or dynamic rendering
- what does the cached or non-cached mean in the data fetching?
- The "revalidate" and "no-store" flags determine whether to use or not use the cache.
- If you are using the "revalidate" or "no-store" options, it means that data fetching is dynamic.
- how about the dynamic functions?
- Dynamic functions rely on information that can only be known at request time such as a user's cookies, current requests headers, or the URL's search params. In Next.
- Using cookies() or headers() in a Server Component will opt the whole route into dynamic rendering at the request time.
- Using useSearchParams() in Client Components will skip static rendering and instead render all Client Components up to the nearest parent Suspense boundary on the client.
- Using the searchParams Pages prop will opt the page into dynamic rendering at the requested time.
- By default, Next.js 13 uses static rendering, which generates all components ahead of time during the build process.
- one more thing, the Rendering Environments (The principle of three-dimensional rendering.)
- There are two environments where your application code can be rendered: the client and the server.
- client and server, one rendering in the client-like browser, one rendering in the server
- Server can refer to computers in regions where your application is deployed to, the Edge Network where your application code is distributed, or Content Delivery Networks (CDNs) where the result of the rendering work can be cached.
- Before React 18, the primary way to render your application using React was entirely on the client.
- However, this led to additional JavaScript needed on the client to make the initial HTML interactive.
- with Server and Client Components, React can render on the client and the server meaning you can choose the rendering environment at the component level.
- for the Page route system, Next.js provided an easier way to break down your application into pages and prerender on the server by generating HTML and sending it to the client to be hydrated by React.
- with Server and Client Components, React can render on the client and the server meaning you can choose the rendering environment at the component level.
- There are two environments where your application code can be rendered: the client and the server.
The three-dimensional rendering involves different layers that perform distinct tasks. However, understanding the server component can be challenging for ReactJS developers since it is a new concept. Previously, all components in React were client-side and could be rendered on either the client or server-side using hydration.
Page route and App route:
Reference