クライアント内のサーバー
CoddyのReactジャーニー「Next.js の基本」セクションの一部 — レッスン 21/47。
ほとんどの人が間違えるルールがここにあります。そして、それこそがサーバーをどこまで活用できるかを決めるルールなのです。
クライアントコンポーネントがサーバーコンポーネントを import することはできません。import すると境界を越えて引き込まれ、それもクライアントコードになってしまいます。そのため、インタラクティブなラッパーの内部にあるものはすべてクライアントコードでなければならないと結論付ける人がいます。しかし、その結論は誤りです。
クライアントコンポーネントは、childrenとして渡されたサーバーコンテンツをレンダリングできます。
違いは誰がレンダリングを行うかです。サーバー ページが次のように記述する場合:
<Panel>
<Details />
</Panel>…server が <Details /> をレンダリングし、完成した結果を prop として Panel に渡します。Panel がそれを import したり、実行したりすることはありません。単にそれをどこに配置するかを決定するだけです。client コンポーネントから見れば、children はすでに完成した UI です。
これにより、小さなインタラクティブなシェル(タブストリップ、モーダル、折りたたみ可能なパネル)が、サーバー専用の大規模なコンテンツをブラウザに引き込むことなくラップできるようになります。インタラクティブな部分は小さなままであり、コンテンツはサーバー上に残ります。
覚えておくべき構造のイメージ: client のラッパー、server の中身。
チャレンジ
中級components/Panel.jsx はクライアントコンポーネントです(ロックされています。内容を確認してください): トグルボタンをレンダリングし、開いているときのみその children を表示します。
現在、ページは詳細をパネルの中ではなく隣にレンダリングしているため、トグルが何も制御できていません。
app/page.jsxで、<p id="details">を<Panel>タグの間に移動して、その children となるようにします。- テキストはそのまま変更せず、
app/page.jsxはサーバーコンポーネントのままにしてください(ディレクティブは追加しない)。
段落自体は引き続きサーバー側でレンダリングされます。クライアントパネルはそれを表示するかどうかだけを決定します。
自分で試してみよう
import './globals.css';
export const metadata = {
title: 'My App',
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。