概要
Next.jsに、ダイナミックルートがあれば良いなあって前々から思っていたけど、Next 9見ていたら増えていたわ。
環境
{
"dependencies": {
"next": "^9.0.0",
"react": "^16.8.6",
"react-dom": "^16.8.6"
},
"devDependencies": {
"@types/node": "^12.6.1",
"@types/react": "^16.8.23",
"prettier": "^1.18.2",
"typescript": "^3.5.2"
}
}
DynamicRouteの使い方
基本的には、ディレクトリ名やファイル名を[fugafuga]/
や[fugafuga].jsx
にするとそこに反応するようになる。
.
├── pages
│ ├── hoge.tsx
│ ├── index.tsx
│ └── kani
│ ├── [kaniname]
│ │ ├── description
│ │ │ ├── [kanitips].tsx
│ │ │ ├── hoge.tsx
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── hoge.tsx
│ └── index.tsx
例えばこのようなフォルダ構成だとする。フォルダ名に"["と"]"がついているので、かなり異様。
3例をほど
localhost:3000/kani/hoge/
にアクセスすると ->pages/kani/hoge.tsx
が読み込まれる。localhost:3000/kani/piyo
にアクセスすると ->pages/kani/[kaniname]/index.tsx
が読み込まれる。
これは大変ありがたい。
localhost:3000/kani/piyo
にアクセスされた時に、pages/kani/[kaniname]/index.tsx
において、useRouter
フックを使うとその中のkaniname
パラメタにpiyo
が入っている。
const KaniName: NextPage = () => {
const router = useRouter();
const { kaniname } = router.query;
return <p>{kaniname}</p>;
};
export default KaniName;
-
localhost:3000/kani/piyo/description/
にアクセスすると ->pages/kani/[kaniname]/description/index.tsx
が読み込まれる。 -
localhost:3000/kani/piyo/piyopiyo/
にアクセスすると ->404
になる
-
localhost:3000/kani/piyo/description/hoge
にアクセスすると ->pages/kani/[kaniname]/description/hoge.tsx
が読み込まれる。 -
localhost:3000/kani/piyo/description/piyopiyo
にアクセスすると ->pages/kani/[kaniname]/description/[kanitips].tsx
が読み込まれる。
こんな感じのデータがあるとして
export interface Kani {
name: string;
description: string;
tips: { title: string; content: string }[];
}
export const kanis: Kani[] = [
{
name: "カニ一郎",
description: "強いカニ",
tips: [
{ title: "強さの秘密", content: "強いから" },
{ title: "生まれ", content: "琵琶湖" }
]
},
{
name: "カニ二郎",
description: "さらに強いカニ",
tips: [{ title: "生まれ", content: "太平洋" }]
},
{
name: "カニ三郎",
description: "さすらいのカニ",
tips: []
}
];
こんかな感じで動的にページを作れる。
const KaniTips: NextPage = () => {
const router = useRouter();
const { kaniname, kanitips } = router.query;
const [kani] = useState(kanis.find(e => e.name == kaniname));
return (
<Layout>
{kani ? (
<>
<h1>
{kani.name}の{kanitips}
</h1>
<hr />
<KaniFactFind kani={kani} kanitips={kanitips} />
</>
) : (
<p>{kaniname}なる奴は知らん</p>
)}
</Layout>
);
};
export default KaniTips;
useRouteの型がanyだったので、JSON.stringifyして見るだけしてみた。あとあと詳しく調べよ思うけど、そのうち治る気がする。
{
pathname: "/kani/[kaniname]/description/[kanitips]",
route: "/kani/[kaniname]/description/[kanitips]",
query: { kaniname: "カニ五郎", kanitips: "強さの秘密" },
asPath:
"/kani/%E3%82%AB%E3%83%8B%E4%BA%94%E9%83%8E/description/%E5%BC%B7%E3%81%95%E3%81%AE%E7%A7%98%E5%AF%86",
events: {}
}
今までは、ページパラメータに情報を食わせて、?やら=やらがたくさん作るURLにするか、Link
にas
をつけてマスクするかなかった。Link
にas
すると何がまずいかと言うとリロードした時に、404とかになる。
<Link href="/kani?kaniname=piyo" as="/kani/piyo">
<a>kani/piyoへと見せかけて/kani?kaniname=piyoへ</a>
</Link>
そのためExpressなりでサーバーを立てなければならなかったが、今回のDynamic Routingが導入されれば、そのようなカスタムサーバを立てる機会が減る。(そら当然、機会が完全に0にはならんけど)
こんな感じにgetInitialProps
してもいいか知ら。
const KaniTips: NextPage<{ kani: Kani }> = ({ kani }) => {
const router = useRouter();
const { kaniname, kanitips } = router.query;
return (
<Layout>
{kani ? (
<>
<h1>
{kani.name}の{kanitips}
</h1>
<hr />
<KaniFactFind kani={kani} kanitips={kanitips} />
</>
) : (
<p>{kaniname}なる奴は知らん</p>
)}
</Layout>
);
};
KaniTips.getInitialProps = async ({ query }) => {
const { kaniname } = query;
return { kani: kanis.find(e => e.name == kaniname) };
};
export default KaniTips;
まとめ
- Next.js 9はDynamic Routeがついている。・・・それは嬉しい❤️
- フォルダ名や、ファイル名に[]がつく景色が出てくるかも
- Next.jsにExpressなり、カスタムサーバーたてる機会がもっと減って、楽チンになるかも
参考
おまけ
できた奴: https://github.com/NanimonoDemonai/dynamic-routing
なんかつくってもいない、description.jsを読みに行こうとして、ないもんだから、404とか吐いているけど、そのうち治るかな