Next.js App Router の末端にある Client Components で懐かしの C/P パターン

C/P = Container/Presentational

タイトルに入れ込むには長かったので...

  • Next.js App Router を使用
  • Client Component の境界を越えた先はクライアントサイドバンドルに載ってしまう
  • よってツリーの末端に移動させるのが最適化の基本方針になる
  • Client Component になる理由は DOM 操作が必要なパターン e.g. <Carousel>
  • もしくはクライアントサイドでのデータ取得が必要なパターン e.g. useQuery()
  • 内部でデータフェッチすると test や storybook でのモックがちと面倒に感じる

サンプルコード

じゃあ局所的な Container/Presentational でいいんじゃね、ということでこんな感じ(大分極端ですがイメージです)

export const ClientSideFetchedList = () => {
  const { data } = useQuery(...);
  return (
    <__ClientSideFetchedList  items={data?.list || []} />
  );
};

export const __ClientSideFetchedList = ({ items }) => {
  return (
    <ul>
      {items.map((item, i) => <li key={i}>{item.name}</li>)};
    </ul>
  );
};

Test や Storybook では <__ClientSideFetchedList> だけを import して取り扱います。

Server Components でも同様のパターンが有効と思われますが、手元では Server Components らしい働きをするのは上位層のコンポーネントのみに留める古典の広域的 Container/Presentational パターンに寄せています。

server の根元と client の末端に寄せていくスタイル

総じて Server Components の根元と、Client Components の末端に処理が寄っていきました。中間のコンポーネントは普通の React Component として取り回せるので現状の App Router 環境の成熟度を鑑みるとアリな気はします。

App Router はともかくとしても storybook や test は不便すぎない程度にシンプルな形を保っておいたほうが、エコシステムのアップデート耐性も上がるのではないかと思う次第。ソフトウェアのメンテナンスコストにおいてサプライチェーンのアップデートが占める割合が高くなりやすい Web アプリケーション界隈はそういうアプローチもありなんじゃないかなと。

勇気

世間的な自信に乏しかったのですが Container/Presentational の適用が下記のリソースでも触れられていたので、勇気を出して手元での例も書いてみました :)


Author

ahomuAyumu Sato

overflow, Inc.VPoE

東京資本で生きる名古屋の鳥類

Web 技術、組織開発、趣味など雑多なブログ。技術の話題は zenn にも分散して投稿しています。

Bio: aho.mu
X: @ahomu
Zenn: ahomu
GitHub: ahomu

Related

Latest

Archives

Tags

Search