Open3

React Server Components 雑まとめ

G4RDSG4RDS

React Server Components 概要

  • サーバーサイドで React コンポーネントをレンダーする新しい技術
  • Facebook がいま研究していて、まだ開発段階
  • React に、Client Components / Server Components という新しい概念を持ち込む
    • Client Components は、従来通りクライアントでのみレンダーされるコンポーネント
      • ステートを持ち、インタラクティビティを持つ
    • Server Components は、サーバーサイドでのみレンダーされるコンポーネント
      • サーバー上のリソースにアクセスするレイテンシを下げられる
      • クライアントへは HTML を返すのではなく、独自のプロトコルを採用
        • JSX を返したり
        • Client Components の読み込み命令を返したり
        • Concurrent Mode の Suspense を返したりする
    • Shared Components というのもあり、場合によって Client / Server どちらでもレンダーできるコンポーネント
      • データフェッチはしないけれど、外部ライブラリを読み込むから必要じゃないならクライアントに読み込ませたくない コンポーネントに使える
      • Server Components から返されるとサーバーサイドで、Client Components から返されるとクライアントサイドで実行される
      • デモでいうと、NotePreview.js コンポーネントは、Note.server.js コンポーネントで呼ばれるときにサーバーサイドでレンダリングされ、NoteEditor.client.js コンポーネントで呼ばれるときにクライアントサイドでレンダリングされる
      • 編集のプレビューをいちいちサーバーでやりたくないので、編集するとなったときに外部ライブラリも読み込めばいいよね
  • Concurrent Mode ともよくマッチする
    • Server Components で Suspense を返すと、そこまでレンダリングしたら一旦クライアントに JSX を返却
    • Suspense が解決したら、レンダー後の JSX を返す
    • ここまで一つのコネクションでストリームする
    • レスポンスの JSX には J6 のようにそれぞれ番号がついていて、JSX の children に @6 のように埋め込んで分裂した JSX をリンクしている
    • J6 が来てないのに @6 が来たら、そこで Suspense して fallback を表示していそう(推測)
G4RDSG4RDS

動作の中身

デモのソースコードを見ながら動作を見ていく。
実装まで見ておらず、かなり推測入っているので注意!

https://github.com/reactjs/server-components-demo

  • React クライアントは読み込まれると、Root.client.jsCache.client.jsuseServerResponse フックを呼び、/react という API にリクエストしている
  • /reactlocation というクエリを受け取る
    • LocationContext の値をそのまま渡している
    • Root.client.js で初期化している
      • selectedId
      • isEditing
      • searchText
  • locationApp.server.js に渡し、サーバーでレンダリングする
  • こんなのを返す

  • 途中で Client Components が現れたら、コンポーネントを読み込むよう Mx を返している

    • x には数値が入っていて、children に @x が入っていると、x に対応する Mx もしくは Jx が入る
  • レンダリングが終わったら、Jx として JSX を返している

    • J0 はルートの JSX
    • 間に Client Components が挟まったり Suspense したりして分割されると、J1, J2, ...と分割されるっぽい
  • 記事を選択すると LocationContext の値が変わってサーバーにリクエストが飛ぶ

    • このとき、レスポンスは useServerResponse でキャッシュしているので、キャッシュヒットしたらリクエストせずにそれを返す
  • 毎回全ての DOM を返しているが、クライアントでうまいことコンポーネントのステートを保持している

    • key を返るとちゃんとコンポーネントが demount されるので、React の Shadow DOM の動作と同じっぽい(よく理解してない)