この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。データアナリティクス事業本部 サービスソリューション部の北川です。
Next.jsで、新しいルーティングシステムについての記事が公式から出ました。
今回は中でも、ようやく提案されたNested Layoutsについて調べたので、まだ正式に実装されたわけではないですが、せっかくなので記事にしました。
Appフォルダの提供
Next.jsでは、pagesフォルダの配下に作成したファイルが、そのままURLのパスとして機能します。
新しいルーティングシステムでは、pagesフォルダではなく、機能追加に対して段階的に変更できるよう、新しくappフォルダを提供する考えのようです。そのため、appフォルダとpagesフォルダは併用できそうです。アップデートによる修正や更新の負担が減るので、これはありがたいです。もちろんpagesフォルダ同様、階層を下げてパスを指定できます。
pagesフォルダと違う点は、appフォルダではファイルではなく、フォルダが一つのパスとして機能するようです。これによる利点は、フォルダの配下にファイルを作成したとしても、そのファイルは一つのページとして認識されない点にあります。そのため、一つのページでしか使用しないUIコンポーネントのファイルや、hooksのファイルをフォルダ配下におけるようになります。
pageExtensions
pagesフォルダでも、pageExtensions機能を使用することで、実装が可能です。
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// 「.bar.tsx」、「.foo.tsx」のファイルがページとして認識される
pageExtensions: ["bar.tsx", "foo.tsx"]
}
module.exports = nextConfig
上記の例だと、拡張子が「.bar.tsx」と「.foo.tsx」のファイルのみページとして認識され、「index.tsx」のようなファイルはパスとして機能しなくなります。
Nested Layouts
NestedLayoutsは、共通部分をまとめたレイアウトを階層ごとに作成することで、その配下のページで複数のレイアウトを適用することができます。Remixでは初期の頃からこの仕様を提供しており、Next.jsとの大きな比較部分でした。
getLayout
一応、Next.jsでレイアウトの分岐を行うには、getLayout()を使用してページごとにレイアウトを指定する方法がありました。
_app.tsx
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { NextPage } from "next";
import { ReactElement, ReactNode } from "react";
type NextPageWithLayout = NextPage & {
getLayout?: (page: ReactElement) => ReactNode;
};
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
const getLayout =
Component.getLayout ||
((page) => {
return page;
});
return getLayout(<Component {...pageProps} />);
}
export default MyApp;
index.tsx
const Sample = () => {
return (
<>
...
</>
);
}
export default Sample;
// LayoutAを適用
Sample.getLayout = LayoutA;
Layouts
レイアウトでは、ファイル内で共通で使うUIを提供します。レイアウトを作成した階層(サブツリー)内のセグメント間で共有できます。レイアウトはパスに影響を与えず、ユーザーがページ間を移動しても再レンダリングされないです。
layout.jsファイルを作成し、コンポーネント内をラッピングすることで機能します。
import { Header } from "layouts/header/header";
import { Footer } from "layouts/footer/footer";
import type { ReactChild } from "react";
export const Layout = ({ children }: {children: ReactChild}) => {
return (
<>
<Header />
<main>
{children}
</main>
<Footer/>
</>
);
};
Sample.tsx
import { Layout } from "../layouts/layouts";
const Sample = () => {
return (
<Layout>
...
</Layout>
);
};
export default Sample;
レイアウトは2つのタイプを提供します。
- Root layout
- Regular layout
2つ以上のレイアウトを入れ子にすることで、Nested Layouts機能を実装できます。
Root layout
ルートレイアウトは、すべてのページに共通するUI、設定を記述します。_appフォルダの直下に、layout.jsを作成することでルートレイアウトとして機能します。これは、_app.jsと_document.jsの大替として提供されるようです。また、、タブのカスタマイズもできます。
Regular layout
特定のフォルダ内に、layout.jsを作成することで通常のレイアウトとして機能します。一部のページにのみ、共通化させるレイアウトを実装したい場合に使用します。
ルートレイアウト、レギュラーレイアウトを組み合わせたり、レギュラーレイアウトを複数作成することで、ネストされたレイアウトを実装することができます。
まとめ
今回は、Nested Layoutsについて、調べてみました。今後の意向が容易になると思うので、これから新規にNext.jsを使用する場合は、pageExtensionsを設定しておくといいのかなと思いました。今後、どのように機能が追加されていくのか楽しみです。
ではまた。