あのサイトを Next.js に載せてみる

この記事は、 [Next.js Advent Calendar 2019](https://qiita.com/advent-calendar/2019/next-js) の 6日目の記事です。

本日の記事は、気楽に読んでいただければ幸いです。


## はじめに

**React + Next.js + Firebase** でのアプリケーション作成の素振りをしようとしていたところ、2年くらい前の「阿○寛のサイトが dev.to 並に早い」というネタを思い出していたこともあって、 **React + Next.js** で組み立て直してみようかとも思いましたが、２年前に[PWA化までしていた記事](https://qiita.com/teckl/items/105d1871c5042e44f60a)もあったので、さらに昔を懐古して、あのサイトのテンプレで「前○プロフ」みたいなサイトを作ってみようと思った次第です。

## 出来上がった黒歴史プロフサイト

![Screen Shot 2019-12-06 at 1.15.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110426/e4fd71ed-ea7b-da39-f21f-15f4a7368b0c.png)


https://ano-site.web.app

※上記サイトは、2019年のアドカレ期間終了後は落としているかもしれません。ご了承ください🙇‍♂️

ソースコードは ↓
[https://github.com/uitspitss/ano-site](https://github.com/uitspitss/ano-site)



## Next.js

今回、**Next.js** を使いこそはしましたが、**React Hooks** にいろんなものを押し込めることができたおかげで、**Next.js** に背負ってもらったのは、ユーザー情報ページへのルーティングとちょっとしたAPIくらいになってしまいました。

### Dynamic Routing

ドキュメントはこちら → [Next.js Documentation #Dynamic Routing](https://nextjs.org/docs#dynamic-routing)

1. server(Express)側も組み合わせた **Dynamic Routing**
2. `[id].js` といったパラメーターページを使った **Dynamic Routing**

の２通りで書いたので、そのあたりの説明を書きたいと思います。

プロフサイトということでページ構成としては、`/` 以降にユーザーID(今回は Twitter アカウントの `Screen Name`)ごとのページが存在する構成になります。
このユーザーIDごとのページを動的に生成するイメージのルーティングなので、その部分を `Next.js` にルーティングしてもらいます。

```
/ ┬─ john
  ├─ thomas
  ├─ julia
  ├─ [screenName]
  .
  .
  .
```

#### 1. server(Express)側も組み合わせたDynamic Routing

↓server(Express)側のコード抜粋

```src/functions/index.ts
server.get('/:screenName', (req: Request, res: Response) => {
  return app.render(req, res, '/', { screenName: req.params.screenName });
});
```

パスで指定した変数に入れて、ページコンポーネント側に渡してあげます。

↓ページコンポーネント側のコード抜粋

```src/app/pages/index.tsx
const IndexPage: NextPage<Props> = ({ screenName }) => {
  const { user: twitterUser, timeline, loading: twitterLoading } = useTwitter(
    screenName,
  );
  const { user: siteUser, loading: siteLoading } = useSiteUser(screenName);

  return (
    <>
      <FirebaseApp>
        <MainColumn
          screenName={screenName}
          siteUser={siteUser}
          twitterUser={twitterUser}
          timeline={timeline}
          loading={twitterLoading || siteLoading}
        />
      </FirebaseApp>
    </>
  );
};

IndexPage.getInitialProps = async ({ query }) => {
  let screenName = query ? query.screenName : null;
  screenName = screenName ? (screenName as string).split(', ')[0] : 'uitspitss';

  return { screenName };
};
```

`getInitialProps` で `query` 内に渡ってくるので、ページコンポーネントに渡します。

デモ: [https://ano-site.web.app/ano_site](https://ano-site.web.app/ano_site)

#### 2. `[id].js` といったパラメーターページを使った **Dynamic Routing**

server側は特にいじりません。

↓ページコンポーネント側のコード抜粋

```src/app/pages/users/[screenName].tsx
const UserPage: NextPage = () => {
  const router = useRouter();
  let { screenName } = router.query;
  screenName = screenName ? (screenName as string).split(', ')[0] : 'uitspitss';
  const { user: twitterUser, timeline, loading: twitterLoading } = useTwitter(
    screenName,
  );
  const { user: siteUser, loading: siteLoading } = useSiteUser(screenName);

  return (
    <>
      <FirebaseApp>
        <MainColumn
          screenName={screenName}
          siteUser={siteUser}
          twitterUser={twitterUser}
          timeline={timeline}
          loading={twitterLoading || siteLoading}
        />
      </FirebaseApp>
    </>
  );
};
```

`useRouter` 経由で `screenName` を拾っています。ここは `withRouter` のHOCを使うこともできるようです。

デモ: [https://ano-site.web.app/users/ano_site](https://ano-site.web.app/users/ano_site)

#### 公式ドキュメント以外の参考にした文献等

- [りあクト！ Firebaseで始めるサーバーレスReact開発](https://oukayuka.booth.pm/items/1572683)
  - React + Firebase のあたりはこの本とサンプルコードをとても参考にしてます。実践的な内容がまとまっていてとても良い本です。
- [実践TypeScript](https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5TypeScript-%E5%90%89%E4%BA%95-%E5%81%A5%E6%96%87-ebook/dp/B07T477V6G)
  - Next.js での TypeScript の扱いなど、こちらも実践的な内容が書かれている本です。
- [With Firebase Hosting and Typescript example](https://github.com/zeit/next.js/tree/canary/examples/with-firebase-hosting-and-typescript)
  - Next.js の React + TypeScript + Next.js のサンプル。Next.jsの[サンプル集](https://github.com/zeit/next.js/tree/canary/examples)は充実していて、今回作ったアプリケーションのような Firebase を組み合わせるケースや、semantic-ui と組み合わせるケースなど、様々なユースケースのサンプルが用意されています。
- [いまみているウェブページを阿部寛のサイトっぽくするChrome拡張を作った](https://qiita.com/kyoyababa/items/b7e80ac4815bcb95a49a)
  - あのホームページの独特感の源である、背景の薄緑文字をCSSで再現する方法を参考にしました。
  - 今回作ったアプリケーションでは、 `src/app/components/CharctersPrintedBackground.tsx` というコンポーネントに実装しました。
- [阿部寛さんのホームページ](http://abehiroshi.la.coocan.jp/)
  - 大変畏れ多いですが、ネタ元です。

## 最後に

今回、Next.js + React + Firebase だけではなく、

- Semantic UI React
- Emotion
- react-hook-form
- i18next(next-i18next)

等々、人気のあるライブラリを触ってみたかったので、アプリケーションを仕立てました。
なので、 Next.js + React + Firebase の参考にでもなれば幸いです。

今月に入った頃から、Semantic-UIのアイコンが読み込めなくなって、原因を探ったり、 Font Awesome に切り替えたりしていたら、時間切れになってしまい、中途半端感ありありです。

ともあれ、このあたりで締めたいと思います。
ちょっと早い時期ですが、みなさま良いお年を〜