【Next.js】管理画面を作りながらNext.jsを学ぶ(ChakraUI/ルーティング)

# まえがき

[前記事](https://qiita.com/crml1206/items/fe8bbb784a28e6d24b80)にて、管理画面をcreate-react-appで作成した。これをNext.jsで作ってみる。

https://nextjs.org/docs/getting-started

# プロジェクト作成
```
yarn create next-app --typescript
```
プロジェクト名を聞かれるので「next-practice」と入力
```
C:\Users\daisu\Desktop\workspace>yarn create next-app --typescript
yarn create v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Installed "create-next-app@12.1.0" with binaries:
      - create-next-app
√ What is your project named? ... next-practice
Creating a new Next.js app in C:\Users\daisu\Desktop\workspace\next-practice.
```

起動
```
yarn dev
```
http://localhost:3000 にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653955/d7e46f3a-a972-1038-be43-f23c368c4598.png)


# プロジェクト構成

素のReactプロジェクト
・src/index.tsxが起点となり、ルートコンポーネントのsrc/App.tsxをレンダリングする

に対して、

Next.jsプロジェクト
・**起点のスクリプトファイルが存在しない**。
・**pages配下のファイルがそのままルーティング設定となる。**
　 - pages/index.tsx → 「/」でアクセス
　 - pages/abount.tsx → 「/about」でアクセス
　 - pages/account.tsx → 「/account」でアクセス
　 - pages/dashboard/index.tsx → 「/dashboard」でアクセス

## pages配下のファイル作成時のポイント
・NextPage型のオブジェクトを戻りとする関数をexportすること
```typescript
import type { NextPage } from 'next'

const Home: NextPage = () => {
  return (
    <div>
       // 省略
    </div>
  )
}

export default Home
```

# 管理画面を作ってみる
・基本的には[前記事](https://qiita.com/crml1206/items/fe8bbb784a28e6d24b80)で作成した素のReactプロジェクト内の各ファイルを、そのままNext.jsプロジェクトに移行する。
・完成形の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653955/703847bb-0c3d-fe3f-b1a2-0321f0a738f1.png)

必要なコンポーネントを並べるとこんな感じ

　pages/
　・index.tsx（TOP画面）
　・account.tsx（Account管理画面）
　・charts.tsx（Charts管理画面）
　・dashboard.tsx（Dashboard管理画面）
　・mailBox.tsx（MailBox管理画面）
　・message.tsx（Message管理画面）
　・rateReview.tsx（RateReview管理画面）
　・weather.tsx（Weather管理画面）

　components/
　・TopHeader.tsx（ヘッダー）
　・SideMenu.tsx（サイドメニュー）
　・account/AccountTable.tsx（Accountテーブル）

　public/
　・sampleLogo.PNG（ヘッダ画像）
　・data/accounts.json（Account一覧取得APIの戻り値用）

また、Next.jsでChakraUIを使うために必要なライブラリをインストールしておく。
```
yarn add -D @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
```

https://fwywd.com/tech/next-chakra-ui

## Next.jsでのルーティング設定

素のReactプロジェクトでは**react-rooter**を利用してルーティング設定をルートコンポーネントに定義した。
```typescript
import { BrowserRouter, Routes, Route } from "react-router-dom";

export const App = () => {
  return (
    <ChakraProvider theme={theme}>
      <Flex w="100vw" h="100wh">
        <TopHeader />
        <Box mt="100px">
          <Flex>
            <BrowserRouter>
              <SideMenu />
              <Box w="70vw">
                <Routes> // 画面ごとにルーティング設定
                  <Route path="/" element={<Dashboard />} />
                  <Route path="/account" element={<Account />} />
                  <!-- 以下省略 -->
                </Routes>
              </Box>
            </BrowserRouter>
          </Flex>
        </Box>
      </Flex>
    </ChakraProvider>
  );
};
```
Next.jsプロジェクトでは、先述した通り「**pagesディレクトリに配置したファイルがそのままルーティング設定**」となる。


## Next.jsでのレイアウト設定
レイアウトのような、どの画面でも表示したいものは**pages/_app.tsx**に定義する。
```typescript
import '../styles/globals.css'
import type { AppProps } from 'next/app'

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

export default MyApp
```
今回追加すべきものとしては「レイアウト用コンポーネント」と「ChakraProvider」があるので、↓のようになる。
```typescript
import type { AppProps } from 'next/app'
import { ChakraProvider, Box, Flex, theme } from "@chakra-ui/react";
import { TopHeader } from '../components/TopHeader';
import { SideMenu } from '../components/SideMenu';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider theme={theme}>
      <Flex w="100vw" h="100wh">
        <TopHeader />
        <Box mt="100px">
          <Flex>
            <SideMenu />
              <Box w="70vw">
                <Component {...pageProps} />
              </Box>
          </Flex>
        </Box>
      </Flex>
    </ChakraProvider>
  );
}

export default MyApp
```

## アイコンクリック時に画面遷移するようにする
素のReactプロジェクトでは**react-router-dom**のuseNavigate関数を用いていた。
```typescript
<script lang="ts">
  import { useNavigate } from "react-router-dom";
</script>

<Button variant="ghost" onClick={() => navigate(item.path)}>
  <Icon as={item.icon} w={7} h={7} mr="13px" />
  {item.name}
</Button>
```
Next.jsプロジェクトでは**next/router**を利用する。

https://nextjs.org/docs/api-reference/next/router#userouter

```typescript
import { useRouter } from 'next/router'

export const SideMenu = () => {
  // useRouter関数でrouterオブジェクト取得
  const router = useRouter();
  const sideMenuItems = [//省略];
  return (
    <Box w="20vw" m="20px">
      {sideMenuItems.map((item) => (
        <label>
          <Box mt="10px" ml="10px">
            // router.push()で画面遷移
            <Button variant="ghost" onClick={() => router.push(item.path)}>
              <Icon as={item.icon} w={7} h={7} mr="13px" />
              {item.name}
            </Button>
          </Box>
        </label>
      ))}
    </Box>
  );
};
```

# まとめ（素のReactとNext.jsの違い）
違いをあげれば他にも沢山挙げられると思うが、本記事では以下の３つを違いとして取り上げる。

## ルーティング設定
素のReact
　・"react-router-dom"を使う。
　・`BrowserRouter,Routes,Route`で画面ごとにルーティング設定する必要がある。
Next.js
　・**pagesディレクトリ配下のファイルが、自動でルーティング設定に落とし込まれる。**
## レイアウト設定
素のReact
　・src/App.tsxにてレイアウト設定
Next.js
　・**pages/_app.tsxにてレイアウト設定**
## クリックによる画面遷移
素のReact
　・react-router-domのuseNavigate関数を使う。
Next.js
　・**next/routerのuseRouter関数を使う。**