Next13のレイアウトを試してみる
先日リリースされたNext.js v13のレイアウトを試してみます。
設定
以前はpages/**/*.tsxに配置していましたが、v13からはapp/**/page.tsxとして配置することで、親ルートのレイアウトからネストした状態のページを簡単に作成できるようになりました。
使用するためにはnext.config.jsの変更が必要です。
experimental.appDirをtrueに変更します。
また、pagesディレクトリは不要となるため、削除します
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
experimental: {
appDir: true,
},
}
module.exports = nextConfig
app以下の各種ファイル
- page.tsx ... ページ固有のUIを定義ファイル。自動的に親ルートからのレイアウトと、現在のルートのレイアウト内にマウントされます。
- layout.tsx ... レイアウトの定義ファイル
- error.tsx ... エラーが発生した際に表示されるUIの定義ファイル。React Error Boundaryで自動的にWrapされるとのこと
- template.tsx ... layoutと似ていますが、ページ遷移の度にアンマウントされ、状態がリセットされます
- head.tsx ... ページのhead情報を設定します
今回はpage.tsxとlayout.tsxのみ使用します。
/appにlayout.tsxと、page.tsxを作成します。
import { FC, ReactNode } from 'react';
type Props = {
children?: ReactNode;
}
const HomeLayout: FC<Props> = ({ children }) => {
return (
<div
style={{
padding: '20px',
background: '#ddd',
}}
>
{children}
</div>
);
};
export default HomeLayout;
import { FC } from 'react';
const HomePage: FC = () => {
return (
<div>
Hello!
</div>
);
};
export default HomePage;
devServerを起動し、localhost:3000にアクセスしてみます。
yarn dev
レイアウトが反映されていることがわかります。
/appに hogeというディレクトリを作成し、
/hoge/page.tsxを作成してみます。
import { FC } from 'react';
const HogePage: FC = () => {
return <div>Hoge!</div>
}
export default HogePage;
localhost:3000/hogeにアクセスしてみます。
親ルートのレイアウトが引き継げています!
ルートは違うが、同じレイアウトを使いたい
下層ページが親ページのレイアウトをネストできることはわかりましたが、ルートはそれぞれ違うけれど同じレイアウトを使いたいことがあると思います。
その場合は、ディレクトリ名を「()」で括った名前にすることで、共通のレイアウトを使用できます。
/appに(guest)というディレクトリを作成し、
直下にlayout.tsxを作成します。
import { FC, ReactNode } from 'react';
type Props = {
children?: ReactNode;
}
const GuestLayout: FC<Props> = ({ children }) => {
return (
<div
style={{
padding: '20px',
background: '#daa',
}}
>
{children}
</div>
);
};
export default GuestLayout;
/app/(guest)にloginと、guestという名前のディレクトリを作成します。
それぞれのディレクトリにpage.tsxを作成します
import { FC } from 'react';
const LoginPage: FC = () => {
return <div>this is login page.</div>
}
export default LoginPage;
import { FC } from 'react';
const RegisterPage: FC = () => {
return <div>this is register page.</div>
}
export default RegisterPage;
localhost:3000/loginとlocalhost:3000/registerにアクセスしてみます。
(guest)で設定したレイアウトがそれぞれのルートで適用されています!
ダイナミックルート
[id]/page.tsxというような構成にすることで、ダイナミックルートを作成できます。
(idではなく、slugなど、他の単語でもOK)
/app/post/[id]に、page.tsxを作成してみます。
import { FC } from 'react';
type Props = {
params: { id: string };
};
const PostPage: FC<Props> = ({ params }) => {
return <div>this is post {params.id} page.</div>;
};
export default PostPage;
ダイナミックルートでは、Propsとしてparamsを受け取ることができます。paramsの中には、[id]でアクセスした際のパスパラメータが入っています。
クエリパラメータを取得したい場合は、searchParamsというパラメータから参照することができます。
localhost:3000/post/1にアクセスしてみます。
指定されたパスパラメータでアクセスすることができました!
以上!
Discussion