📑

[Next.js][App Router]Client Componentを使ってServer ComponentをLayoutする

2023/06/21に公開

たとえば、以下のようにChakra UIのGridを使って、Server Componentをレイアウトしたい場合。

"use client";
import { Grid, GridItem } from '@chakra-ui/react';
import { Body } from './Body';
import { Footer } from './Footer';
import { Header } from './Header';

function Sample() {
  return (
    <Grid>
      <GridItem><Header /></GridItem>
      <GridItem><Body /></GridItem>
      <GridItem><Footer /></GridItem>
    </Grid>
  );
}

※ Header, Body, Footer のいずれか、または全てが、Server Componentでなければならないとします。(next/headers を使うなど)

このコードは、Client ComponentからServer Componentをimportしているため、エラーになります。

解決策

レイアウト用のComponentを別ファイルに切り出して、それを利用します。

'use client';
import { Grid, GridItem } from '@chakra-ui/react';

type Props = {
  header: React.ReactNode;
  body: React.ReactNode;
  footer: React.ReactNode;
};

export function PageLayout({ header, body, footer }: Props) {
  return (
    <Grid>
      <GridItem>{header}</GridItem>
      <GridItem>{body}</GridItem>
      <GridItem>{footer}</GridItem>
    </Grid>
  );
}
import { Body } from './Body';
import { Footer } from './Footer';
import { Header } from './Header';
import { PageLayout } from './PageLayout';

function Sample() {
  return (
    <PageLayout
      header={<Header />}
      body={<Body />}
      footer={<Footer />}
    />
  );
}

これで、Client ComponentからServer ComponentをimportせずにLayoutを実現できます。

何が嬉しいか

Layout側でSuspenseを使って、部分ごとにfallbackを設定できるのが嬉しい点です。

export function PageLayout({ header, body, footer }: Props) {
  return (
    <Grid>
      <GridItem>
        <Suspense fallback={<Loading />}>{header}</Suspense>
      </GridItem>
      <GridItem>
        <Suspense fallback={<Loading />}>{body}</Suspense>
      </GridItem>
      <GridItem>{footer}</GridItem>
    </Grid>
  );
}

参考資料

Next.jsのドキュメントの以下のあたりに、propsで渡す(通常はchildren)方法が書かれています。
https://nextjs.org/docs/getting-started/react-essentials#nesting-server-components-inside-client-components

Discussion