📚

[Next.js]RSCとRCCを分かりやすく定義して混乱を防ぐ

2025/02/28に公開

問題提起

ReactとNext.jsはサーバーコンポーネント(RSC)とクライアントコンポーネント(RCC)の2種類のコンポーネントを扱えます。

import 'server-only'を使うと必ずRSCとしてレンダリングされ、'use client'を使うとRCCとしてレンダリングされます。
(正確に言うと、server-onlyを付けることでRCCとして動かそうとするとエラーになる)

問題になるのが何もつけなかったときで、これは親コンポーネントと同じ属性でレンダリングされます。
そのため、何もつけないコンポーネントはRSCとしてもRCCとしても動くコンポーネントでなければなりません。
しかし単純にimport 'server-only'use clientも書き忘れている可能性もあります。
また、親コンポーネントが明確であるため記述を省略しているかもしれません。
このようなコンポーネントは意図しない場所からインポートされ、エラーが発生する可能性があります。

今回はその対策を考えてみます。

対象読者

  • Next.jsを使って開発をしているフロントエンドエンジニア
  • チーム開発でコンポーネントの管理を明確にしたいと考えている人

提案内容

'use client'ディレクティブについて、Next.jsの公式ドキュメントでは、以下のように説明されています。

"use client" is used to declare a boundary between a Server and Client Component modules. This means that by defining a "use client" in a file, all other modules imported into it, including child components, are considered part of the client bundle.

Next.jsドキュメント - Using Client Components in Next.js

'use client'はRCCとしてレンダリングされる境界を示すと書かれています。
これは正しいのですが、'use client'は境界以外に記述してもよいです。
そして、私はすべてのRCCに'use client'を書くことを提案します。

コンポーネントを定義してから、それを使って画面を組み立てる以上、実装時にはどこが境界になるか分からないことがよくあります。
また、コンポーネントが意外なところで使われる可能性もあります。
そのため、チーム開発では以下のルールを守るのが無難です。

提案ルール

  1. RSCとして定義したコンポーネントにはimport 'server-only'を必ずつける
  2. RCCとして定義したコンポーネントには'use client'を必ずつける
  3. どちらでも動かせるコンポーネントに'use universal'と書く

'use universal'に特別な意味はありませんが、あえて書きます。
何も書かないことに意味を持たせると「書き忘れなのか、意図的に書いていないのか」が判断できません。
そのため、RSCでもRCCでも動作するコンポーネントには明示的に'use universal'と記述するとレビュー時や後から見返したときにすぐに理解できます。
eslintでディレクティブが何も書かれていないコンポーネントはエラーにすることで、さらに統制を強められるでしょう。

このように明示的に分類することで、意図しない動作を防ぎ、チーム開発における混乱を減らすことができます。

Discussion