React Server Component
- サーバー側でJavaScript(async, await)でdata fetchしたのち、Reactを完全にただのHTMLに変換する。その後クライアント側には、JS抜きでHTMLとCSSしか運ばないので、通信量が軽くなり、運ぶ時間が短くなる
- クライアント側にはJavaScriptは運ばれないので、クライアント全体のJSバンドルサイズが減り、それによりJSバンドルの時間が減る
- クライアント全体のJSのバンドルサイズが減るため、ハイドレーションの時間が減る
- ハイドレーションはJSをHTMLに染み込ませることなので、サバコン自体にハイドレーションはないが、クラコン分がある。
上3つの観点で、リクエストを送ってからページが表示されるまでの時間が短縮される。
RSCとSSRは違う
SSR: サーバー側でreact tree全体に対してHTMLに変換する処理を行い、クライアント側ではhydrationだけ行う形式。
RSC: react treeのうち、サーバー側でだけHTML変換するノード(コンポーネント)を指定することができ、指定しなかったノードはクライアント側でHTML変換(ハイドレーションか?)される。data fetchなどサーバー側のrenderだとより都合の良いノードを選び、パフォーマンスを最適化する。
クラコンにサバコンをimportはできない
Server Componentはサーバー時点でReactからHTMLに変換される。そのため、クライアントに運ばれる際の、関数コンポーネント分のバンドルサイズが減る。
サバコンはサーバー側でReactからHTMLに完全に変わったあとにクライアントに運ばれるから、クラコンで、サバコンをimportして使うことができない。なぜなら、コードに記載してるのはReact状態のサバコンだけど、実際にクラコンがimportするときのサバコンはただのHTMLとなっていて、React状態ではなく差異があるから。
しかしchildrenを使うと実現できる。
SSRとRSCのHTML変換とAppRouter
SSRではサーバー側で完成形のHTMLを生成してクライアントに返すが、RSCでは仮想DOMを返す。 RSCも、サバコンはHTML化されて返される。
App Routerキャッシュを無効化したり、動的関数cookies()、headers()を使用したRSCは、自動的に動的レンダリング(SSR)になる。
従来型=CC(クライアントコンポーネント)と置き換えて読んでよいと思う。
サバコン・クラコンの使い分け表
わかりやすい。
Q. サバコンからクラコンをimportしてもエラーにならないのはなぜか
A. React Tree的には、サーバー時点ではクラコンにプレースホルダー(空のnode)が入るため。
サーバー側で、サバコンはReact to HTMLされた後、文字列にシリアライズされ、まだ中身のないクラコンも文字列にシリアライズされる。
クラコンの文字列はこんな感じのjsonで、モジュール参照オブジェクトと呼ばれる。
このjsonが空のnodeとして機能するので、サーバー時点でサバコンはクラコンを正常にimportできている(中身はまだないが)。
以下は、サーバーでReact to HTMLをしたあとのReact Treeを可視化した図。
RSCとSuspense、Streaming
サバコンでSuspenseを使うと、サーバー側で、data fetchができてないなどローディング状態のときに、コンポーネントを、上記のモジュール参照オブジェクトとして出力する。
そこから準備が出来次第、Reactコンポーネントを作り、それをHTMLに変換してクライアントに送る。
Streamingとは、HTMLを小さなチャンクに分解し、その塊チャンクをサーバーからクライアントに順次送信する仕組みのこと。
もともとページ全体でしか送信ができなかったSSR用の概念だったようだが、それが今はRSCにも適用されている(ように見える)。
RSCもStreamingもパフォチューの概念であり、そのため今はそれらを併用した以下のような形でやってくのがベターだと思われる。
Dan Abramov先生のRSC解説
最近のReact事情がとてもよくまとまってるスライド
わかりやすい図。
dan先生の図。
use clientは、その子供以降全部client componentっていう境界線を示すもののよう。
RSCはGraphQLやBFFを代替するものだ、という意見。