Next.js 9にDynamic Routingが付いた、それは嬉しい

# 概要
[Next.js](https://github.com/zeit/next.js)に、ダイナミックルートがあれば良いなあって前々から思っていたけど、Next 9見ていたら増えていたわ。


# 環境
```json:package.json
{
  "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

```
例えばこのようなフォルダ構成だとする。フォルダ名に"**[**"と"**]**"がついているので、かなり異様。

３例をほど

* `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`が入っている。

```tsx
const KaniName: NextPage = () => {
  const router = useRouter();
  const { kaniname } = router.query;
  return <p>{kaniname}</p>;
};
export default KaniName;

```
![スクリーンショット 2019-07-08 2.11.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/5b9e8741-db00-9bbc-c4d2-05b702423941.png)

----------


* `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`が読み込まれる。

こんな感じのデータがあるとして

```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: []
  }
];
```

こんかな感じで動的にページを作れる。

```tsx:pages/kani/[kaniname]/description/[kanitips].tsx
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;
```

![スクリーンショット 2019-07-08 2.21.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/7942098b-87a1-2e50-42f1-af3fbc9b729a.png)

![スクリーンショット 2019-07-08 2.25.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/9ad9034e-99d5-3750-9400-124f85c17f92.png)

![スクリーンショット 2019-07-08 2.25.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/bdca0544-405e-4805-2ef7-9f9de9cbbb82.png)

useRouteの型がanyだったので、JSON.stringifyして見るだけしてみた。あとあと詳しく調べよ思うけど、そのうち治る気がする。

```js:routerの中を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とかになる。

```tsx:
<Link href="/kani?kaniname=piyo" as="/kani/piyo">
      <a>kani/piyoへと見せかけて/kani?kaniname=piyoへ</a>
</Link>
```

そのためExpressなりでサーバーを立てなければならなかったが、今回のDynamic Routingが導入されれば、そのようなカスタムサーバを立てる機会が減る。（そら当然、機会が完全に0にはならんけど）

こんな感じに`getInitialProps`してもいいか知ら。

```tsx:pages/kani/[kaniname]/description/[kanitips].tsx
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なり、カスタムサーバーたてる機会がもっと減って、楽チンになるかも

# 参考
* [Dynamic Routing](https://github.com/zeit/next.js#dynamic-routing)
* [next.js/examples/dynamic-routing/](https://github.com/zeit/next.js/tree/canary/examples/dynamic-routing)

### おまけ
できた奴： https://github.com/NanimonoDemonai/dynamic-routing

なんかつくってもいない、description.jsを読みに行こうとして、ないもんだから、404とか吐いているけど、そのうち治るかな