🐯

[Next.js] SSR と React Server Components の相違点を理解する

2023/09/01に公開

概要

最近、実務の中で Next.js version 13 の App Router で実装する機会をいただきました。
しかし、実際に使ってみたところ、SSR と React Server Components をごっちゃに解釈してしまい、よくわからないことになってしまいました。そのため、今回の記事で自分の中での SSR と React Server Components について一旦整理しよう、ということで今回の記事を作成しました。

https://nextjs.org/docs/app

公式のドキュメントを参照しながらまとめたため、大きな解釈違いはないと思っているのですが、間違っている箇所などあれば気軽にご指摘いただけると嬉しいです。

SSR とは

まず、SSR について簡単にまとめていこうと思います。
SSR とは、Server Side Rendering の略称で、その名の通り、サーバーサイドでレンダリングすることを指します。具体的には、サーバー側でページの HTML を生成し、それをクライアント(ブラウザ)に返すことで、高速にページを描画できるアプローチのことです。

server side rendering

SSR が採用される以前のクライアント側だけで HTML を生成する方法だと、アプリケーションの初回アクセス時の表示速度によるパフォーマンスの低下や、SEOなどの課題がありました。その課題を改善するために、サーバー側で HTML の生成を行い、それをブラウザ側に提供することで、挙げた課題を解決させました。

そのため、SSR を行うことのメリットは、「コンテンツの初回描画速度の向上」と「SEOの向上」という2点が大きく挙げられます。

https://nextjs.org/learn/foundations/how-nextjs-works/rendering

React Server Components とは

次に React Server Components についてです。
React Server Components は、2023年5月にリリースされた Next.js version 13.4 で使用できるようになった新たな機能で、その名の通り、サーバーでレンダリングされるコンポーネントになります。

この React Server Components が登場したことにより、コンポーネント毎に「クライアントでレンダリングされるコンポーネント」と「サーバーでレンダリングされるコンポーネント」という区別が付けられるようになりました。以下の画像からわかる通り、1つのページの中にクライアントとサーバーそれぞれでレンダリングされたコンポーネントが混在するようになります。

react server components

React Server Components の背景と使い方

この React Server Components ができた背景として、サーバーで生成できるコードはクライアントに送らずサーバーで完結した方が良いよね、という考えからできたようです。
そのため、サーバーコンポーネントとクライアントコンポーネントの使い分けの見分け方としては、サーバーで処理した方が効率が良いコンポーネントかどうかという部分になります。

react server components 使い分けの表

しかし、公式の表から個人的に注目した点として、上から4つ目の「クライアント側の JavaScript を減らす」という部分があります。わかりやすくサーバーに関連する処理(データ取得や機密情報など)だけでなく、クライアントで処理する JavaScript を減らせるならそれもサーバーコンポーネントとして管理するもの、としており「サーバーで処理した方が効率が良いコンポーネント = クライアントでしか処理できないコンポーネント以外」と解釈できます。

また、App Router を使用した Next.js の環境だと、デフォルトがサーバーコンポーネントになっており、クライアントコンポーネントを使用する際に'use client'とファイルの最初に明示しなければなりません。このことも含めて考えると、やはりサーバーコンポーネントを前提として、クライアントでしか処理できないコンポーネントだけクライアントコンポーネントにするという考えが正しいと感じました。新たにサーバーコンポーネントという概念が生まれたため、「何をサーバーコンポーネントにすれば良いか」と考えてしまいがちですが、逆に「何をクライアントコンポーネントにすれば良いか」という視点から実装していく方が考えやすそうだなと感じました。

React Server Components のメリット

React Server Components を利用することのメリットは、「UXの向上」と「サービスの安全性向上」にあります。こちらも公式がメリットとしていくつか挙げてくれているので、それを少し省略しつつ、解釈していこうと思います。

https://nextjs.org/docs/app/building-your-application/rendering/server-components

  • データフェッチ
    サーバーコンポーネントを使用することで、データリソースの近くでデータ取得を行うことができ、クライアントから取得を行うよりも高速で取得が行えます。また、今まではサーバーとクライアントで共にデータ取得を行ったいたところがサーバーのみになるため、データリソースへのリクエスト量が削減されます。

  • セキュリティ
    サーバーコンポーネントを使用することで、トークンやAPIキーなどの機密データとロジックをサーバーだけで完結でき、サービスの安全性が向上します。

  • キャッシュ
    サーバーコンポーネントを使用することで、サーバーでレンダリングされたコンポーネントのキャッシュを行ってくれます。それによって、レンダリング時間やデータフェッチの量が削減され、リクエストから表示までが高速で行えるようになります。

  • バンドルサイズ
    サーバーコンポーネントを使用することで、サーバーでレンダリングしたコンポーネント分だけ、今まで全てクライアントで行っていたレンダリングから削減されるので、サービスのパフォーマンスが向上します。

このように公式の挙げているメリットを見ていくと、個人的な解釈も入りつつではあるのですが、「UXの向上」と「サービスの安全性向上」というところに焦点が当てられていることが感じられるかなと思います。

SSR と React Server Components の相違点

ここでやっと本題に入っていこうと思います。そもそもの話になりますが、この記事を執筆しようと思った最初の疑問は以下のようなものでした。

「React Server Components って SSR みたいなこと?」

こちらの答えについては、以下のディスカッションにありました。

https://github.com/reactwg/server-components/discussions/5

It is important note that RSC and SSR are two very different things (that tend to be used together).

「よく一緒にされるけど、異なるものだよ」 とのことでした。
実際にコードを触ってみたわけではないのですが、他の記事などを読み漁ったところ、React Server Components で生成される成果物としては、以下のようなデータ形式のものらしかったです。

J0: [
    ["$", "h1", null, {
        "children": "Blog 1"
    }],
    ["$", "p", null, {
        "children": "unt aut..."
    }]
]

React Server Components はサーバーでコンポーネントがレンダリングされるが、HTML を生成するわけではないため、SSR のサーバーでページの HTML がレンダリングされるものとは異なる、という状況でした。ですが、ここで Next.js の公式ドキュメントを確認したところ、サーバーコンポーネントのレンダリング方法についての記載を発見しました。

react server componentsのレンダリングの流れ

https://nextjs.org/docs/app/building-your-application/rendering/server-components#how-are-server-components-rendered

サーバー側で行われていることの手順は2つ。1つ目は、サーバーコンポーネントを先ほど記載した特別なデータ形式に変換する。2つ目は、それを HTML としてレンダリングする、というものでした。

ここから読み取れるのは、React 側が提供している React Server Components としては、特別なデータ形式に変換するだけであり、Next.js 側でその特別なデータ形式を元に HTML を生成しているということでした。

そのため、結論として SSR と React Server Components がサーバーで行っていることは、ページとコンポーネントという単位の違いはあれど、同じ HTML を生成しているということになります。


では、SSR と React Server Components が基本的には同じことをしている、と結論づけると、以下のような疑問が生まれます。

「じゃあ、SSR を行っているページで React Server Components を使う意味ないのでは?」

そんなことはありませんでした。記事の序盤に記載している SSR と React Server Components のメリットは、共存させても活かされるものでした。

SSR はページ全体の HTML を事前に生成し、それを高速でクライアント(ブラウザ)に返すことで、「コンテンツの初回描画速度の向上」と「SEOの向上」を図っているアプローチになります。
一方で、React Server Components はサーバーだけで完結できるコンポーネントはサーバーで効率よく処理を済ますことで、「UXの向上」と「サービスの安全性向上」を図っている新たな機能になります。
そのため、一部目的が重複する箇所はあれど、「どちらか一方を採用していたら、どちらか一方は不要」というものではなく、「両方使ったらもっとユーザー体験よくなるし、安全性も上がるよね」 というものだと感じました。

結論として、SSR と React Server Components はやっていること自体はかなり近しいことをやっているが、それぞれに別の目的があり、役割が違いますよということでした。

まとめ

この記事では、SSR と React Server Components についての基本的な説明と、それぞれの違いについてまとめてきました。個人的によくわからなかった部分を明確にすることが目的であったものの、この記事を読んで何かしら学びを得る人がいると嬉しく思います。

一方で、ここまで長々と SSR と React Server Components について記事を書いてきましたが、「個人的にこういう解釈をしました」みたいな部分も断定的に言ってしまっている部分なんかもあったりします。できるだけ公式の言っていることを参考にまとめましたが、間違っている箇所があれば優しく指摘いただけると嬉しいです。

参考にした記事

https://zenn.dev/uhyo/articles/react-server-components-multi-stage
https://zenn.dev/dai_shi/articles/94affd526f4c8a
https://dev.to/sidthesloth92/react-server-components-initial-thoughts-3lml

Discussion