UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Next.js】Next.js 12のReact Server Components

前回のNext.js12のReact18対応のNew Streaming SSRの続き

uga-box.hatenablog.com

次は、React Server Componentsに関して、もう少し詳しいお話を聞く機会があったのでメモ

React Server Components

React Flightとも呼ばれ、RSCと略されるみたい

サーバーサイドで実行されるコンポーネントで、バンドルサイズの削除、サーバーサイドリソースの活用を目的として使用する

RSCの3種類のコンポーネント

お話しを聞いたときにでていた表がめちゃめちゃわかりやすかったので、そのまま抜粋させてもらう

Server Components Client Components Shared Components
拡張子 .server.js .client.js その他
実行場所 サーバのみ クライアントのみ クライアントとサーバ
状態(useState、useReducerなど) x o x
作用(useEffect、useLayoutEffectなど) x o x
DOMアクセス(実DOM, onClick、onChangeなど) x o x
サーバ側リソースの利用 o x x
Server Componentsの利用 o x x
Client Componentsの利用 o o o
Shared Componentsの利用 o o o

Server Componentsを使う場合、従来のクライアントサイドでデータフェッチするようなコンポーネントが、サーバーサイドでレンダリングされるようになるのでデータフェッチもサーバーサイド行われる

これによりバックエンドが近くなることや、Server ComponentsそのものがAPI Gatewayになるといったメリットがある

RSCのレンダリング

コンポーネント単位でサーバーにアクセスすると思っていたが、そうではなくコンポーネントツリー単位でアクセスするとのこと

つまり、起点はServer Componentsだが、その子コンポーネント(Client ComponentsやShared Componentsも利用できる)も含まれている

HTTPレスポンスは独自のFlightプロトコルというものが使われ、以下のような改行区切りの「タグ:JSON」がフォーマットになる

M1: {"id":"./components/page.client.js","name":"default","chunks":[]}
S2: {"react.suspense"}
M4: {"id":"./components/footer.client.js","name":"default","chunks":[]}
J0: ["$","@1",null,{"children":[["$","$2",null,{"fallback":["$","div",null,{"className":"spinner"}],"children":"@3"}],...]}]
M23: {"id":"./components/story.client.js","name":"default","chunks":[]}

コンポーネントツリーが Server Components > Client Components となっている場合、以下のようにその下に Server Components を呼び出すことはできない

Order.server.js

import OrderView from "./OrderView.client"

const Order = ({orderId}) => {
  const data = useOrderData(orderId)

  return (
    <OrderView orderId={orderId} data={data}  />
  )
}

OrderView.client.js

import OrderItems from "./OrderItems.server" // ←これはNG
const OrderView = ({orderId, data}) => (<>
  <div>
  {data}
  </div>
  <OrderItems orderId={orderId}
</>)

なので、以下のようにServer ComponentsがClient Componentsの子であるServer Componentsをレンダリングする

Order.server.js

import OrderView from "./OrderView.client"
import OrderItems from "./OrderItems.server"

const Order = ({orderId}) => {
const data = useOrderData(orderId)

return (
  <OrderView data={data}>
    <OrderItems orrderId={orderId} />
  </OrderView>
  )
}

OrderView.client.js

const OrderView = ({data, children}) => (<>
  <div>
  {data}
  </div>
  {children}
</>)

このような作りにこれからなるみたい

大枠の概念は理解することができた