📑
[Next.js][App Router]Client Componentを使ってServer ComponentをLayoutする
たとえば、以下のように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)方法が書かれています。
Discussion