てらブログ

てらブログ

日々の学習の備忘録

How React server components work: an in-depth guideを読んでServer Componentsについて理解する

目的

How React server components work: an in-depth guideを読んで要点整理する。

参照:
How React server components work: an in-depth guide

RSCって何?

React server components (RSC)はエキサイティングな新機能で、近い将来、ページロードのパフォーマンスやバンドルサイズ、そしてReactアプリケーションの書き方に大きな影響を与えるらしい。
サーバーとクライアント(ブラウザ)が協力してReactアプリケーションをレンダリングすることを可能にした。つまり一部のコンポーネントをサーバーがレンダリングし、一部のコンポーネントをブラウザがレンダリングすることを可能にした。

Server Side Rendering(SSR)と一緒?

違う。SSRはReactツリーを生のhtmlにレンダリングする環境をシミュレートするもので、サーバーとクライアントのコンポーネントを区別せず、同じようにレンダリングする。一旦SSRは置いておくのが吉。

RSCはここがすごい

RSC以前は、Reactコンポーネントはすべて「クライアント」コンポーネントで、すべてブラウザで実行された。では、なぜサーバー上で何かをレンダリングしたいのだろうか?それは、サーバー上でのレンダリングには、ブラウザよりも優れている点があるからだ。

  • サーバーはデータソースとより密接に連携しているため、ブラウザよりも迅速にデータを取得することができる
  • 重いコードモジュールを楽に利用することができる

つまり、RSCは、サーバーとブラウザーがそれぞれ得意とすることを可能にする。サーバーコンポーネントはデータのフェッチとコンテンツのレンダリングに集中でき、クライアントコンポーネントはステートフルなインタラクティブ性に集中できるため、ページロードが速くなり、javascriptバンドルサイズが小さくなり、ユーザーエクスペリエンスが向上する。

別の言い方をすれば、RSCは役割分担を可能にするためのもの。サーバーができることを前もってやっておき、残りはブラウザに任せる。

サーバーコンポーネント・クライアントコンポーネントの分割
拡張子によって使用できるコンポーネントが変わる。.server.jsxだとサーバーコンポーネント、.client.jsxだとクライアントコンポーネント、どちらでもなければ両方のコンポーネントを使用できる。

また、大事なことは、クライアント・コンポーネントはサーバー・コンポーネントをインポートできない。以下の例はだめ。

// ClientComponent.client.jsx
// NOT OK:
import ServerComponent from './ServerComponent.server'
export default function ClientComponent() {
  return (
    <div>
      <ServerComponent />
    </div>
  )
}

ただし、ReactNodesのpropsとして取り込むことはできる!

// ClientComponent.client.jsx
export default function ClientComponent({ children }) {
  return (
    <div>
      <h1>Hello from client land</h1>
      {children}
    </div>
  )
}

// ServerComponent.server.jsx
export default function ServerComponent() {
  return <span>Hello from server land</span>
}

// OuterServerComponent.server.jsx
// OuterServerComponent can instantiate both client and server
// components, and we are passing in a <ServerComponent/> as
// the children prop to the ClientComponent.
import ClientComponent from './ClientComponent.client'
import ServerComponent from './ServerComponent.server'
export default function OuterServerComponent() {
  return (
    <ClientComponent>
      <ServerComponent />
    </ClientComponent>
  )
}

RSCの詳細

1. サーバーがレンダリング要求を受け取る
"ルート "コンポーネントは常にサーバー・コンポーネントであり、他のサーバーまたはクライアント・コンポーネントレンダリングする可能性がある。

2. サーバーはルート・コンポーネント要素をJSONシリアライズする。
サーバーはルート・サーバー・コンポーネントを、ベースとなるhtmlタグとクライアント・コンポーネントのツリーにレンダリングする。そしてこのツリーをブラウザに送信し、最終的にブラウザでレンダリングを行うことができる。

クライアント・コンポーネントやベースとなるhtmlタグに渡すすべてのpropもシリアライズ可能でなければならない。つまり、サーバコンポーネントから、イベントハンドラをpropとして渡すことはできない!

// NOT OK: server components cannot pass functions as a prop
// to its descendents, because functions are not serializable.
function SomeServerComponent() {
  return <button onClick={() => alert('OHHAI')}>Click me!</button>
}

3. ブラウザがReactツリーを再構築する
ブラウザはサーバーからJSON出力を受信し、ブラウザでレンダリングされるようにReactツリーの再構築を開始する。

残タスク

シリアライズやモジュール参照など、RSCをより正確に理解するヒントがあった為、改めて深堀りしたい。
今後ドキュメントを参照したり、ハンズオンをしたりしながら身につけていく予定。