「Next.js + Chakra UI」で爆速ログイン画面構築

Next.jsのハンズオン、2つ目の投稿です。

↓ 前回の投稿 ↓

https://qiita.com/mayu_AJ/items/6743be31300d6630c1d5

## この記事でできること
1. Chakra UIのインストール・セットアップ
1. [Chakra UI公式のチュートリアル](https://www.youtube.com/watch?v=wI2vqXsjsIo)の理解
    * 以下の写真のような、簡単なログイン画面の作成
    * カラーモードを変更する機能の作成
![clipboard (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/060d72e0-4cda-1e90-3253-9c2b0af250b1.png)


## 手順の前提
* VSCodeがインストールされていること。
* TypeScriptのバージョンが **4.1.0** 以上であること。（理由については[ こちら ](https://chakra-ui.com/getting-started/nextjs-guide#notes-on-typescript-)を参照）
* Next.js 13 がインストールされていること。

:::note
Next.jsがインストールされていない場合は、【 [ 「Next.js + AWS」を使用して、Webサイトを爆速で公開する#1～#7 ](https://qiita.com/mayu_AJ/items/6743be31300d6630c1d5)】などの記事を参考にインストール・セットアップする。
:::

## 手順
### 1.Chakra UIの導入
Chakra UI公式が出している[ Next.jsでのChakra UIの始め方 ](https://v2.chakra-ui.com/getting-started/nextjs-app-guide)に沿って進めていく。

#### 1.1. Chakra UIのインストール
VSCodeのターミナルで以下のコマンドを実行する。
```
npm i @chakra-ui/react@2 @chakra-ui/next-js @emotion/react @emotion/styled framer-motion
```

#### 1.2. Provider Setup
**appディレクトリ内** に「 **providers.tsx** 」を作成する。
![clipboard (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/17f457cc-6116-bf81-8be7-657c9bc9e114.png)

作成した「providers.tsx」に以下の内容を記述する。
```jsx:providers.tsx
'use client'

import { CacheProvider } from '@chakra-ui/next-js'
import { ChakraProvider } from '@chakra-ui/react'

export function Providers({ children }: { children: React.ReactNode }) {
    return (
        <CacheProvider>
            <ChakraProvider>
                {children}
            </ChakraProvider>
        </CacheProvider>
    )
}
```

#### 1.3. App Directory Setup
デフォルトで作成されている「 **app/layout.tsx** 」を編集する。
インポート文に以下のコードを追加する。
```jsx
import { Providers } from './providers';
```

デフォルトで記述されている「 **RootLayout関数** 」を以下のように編集する。
```diff_jsx:app/layout.tsx
export default function RootLayout({ children, }: { children: React.ReactNode }) {
  return (
-    <html lang="en">
-	   <body className={inter.className}>{children}</body>
+    <html lang="ja">
+      <body className={inter.className}>
+        <Providers>
+          {children}
+        </Providers>
+      </body>
    </html>
  )
}
```

インポート文より、以下のコードを削除する。（Chakra UIを導入するとCSSファイルは不要になるため）
```jsx
import './globals.css'
```

<details><summary>サンプルコード</summary>

```jsx:app/layout.tsx
import { Inter } from 'next/font/google'
import { Providers } from './providers';

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children, }: { children: React.ReactNode }) {
  return (
    <html lang="ja">
      <body className={inter.className}>
        <Providers>
          {children}
        </Providers>
      </body>
    </html>
  )
}
```
</details>

### 2.画面を作成してみる

[公式が出しているチュートリアル動画](https://www.youtube.com/watch?v=wI2vqXsjsIo)に沿って、ライトモード / ダークモードが切り替え可能なログイン画面を作成してみる。
サンプルとして、ここではデフォルトで作成されている「 **app/page.tsx** 」を編集していく。

#### 2.1. 'use client' について
デフォルトで記述されている内容をすべて削除し、以下のコードを記述する。
```jsx
'use client'
```

:::note warn
Chakra UIを使用するためには、 **全ての「page.tsx」の先頭行** に上記のコードを記述しなければならない。（理由は公式ドキュメントより [#Setup Provider](https://v2.chakra-ui.com/getting-started/nextjs-app-guide#setup-provider) を参照）
:::

#### 2.2. 見た目を作成する
2.1 で記述したコードの下に、以下のコードを記述する。
```jsx
export default function Home() {
  return (
    <Flex height="100vh" alignItems="center" justifyContent="center">
      <Flex direction="column" background="gray.100" padding={12} rounded={6}></Flex>
    </Flex>
  )
}
```
※ [いろいろな参考資料](#参考サイト-まとめ)は後述

以下の画面のときに **＠chakra ui/react の Flexコンポーネント** を選択すれば、インポート文が自動で追加される。
![clipboard (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/664b2eb1-a315-cce4-488c-e2e283aded1b.png)

手動で追加する場合は、以下のコードを **「'use client'」と「Home関数」の間** に追加する。
```jsx
import { Flex } from "@chakra-ui/react"
```

上記のコードを記述すると、以下のようなグレーで角丸の空のFlexボックスが、画面の中央に作られる。
![clipboard (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/73fad735-8284-a78e-cc04-166c48e9876d.png)

次は、作成したFlexボックスに要素を追加する。
「page.tsx」を以下のように修正する。
```diff_jsx:app/page.tsx
'use client'

import { Button, Flex, Heading, Input, } from "@chakra-ui/react";

export default function Home() {
  return (
    <Flex height="100vh" alignItems="center" justifyContent="center">
      <Flex direction="column" background="gray.100" padding={12} rounded={6}>
+        <Heading mb={6}>Log in</Heading>
+        <Input placeholder="sample@sample.com" variant="filled" mb={3} type="email" />
+        <Input placeholder="********" variant="filled" mb={6} type="password" />
+        <Button mb={6} colorScheme="teal">Log in</Button>
+        <Button>Toggle Color Mode</Button>
      </Flex>
    </Flex>
  )
}
```
※ [いろいろな参考資料](#参考サイト-まとめ)は後述

これで見た目は完成。
![clipboard (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/65968e12-f280-a8a1-58b6-a8f974310858.png)

この段階で以下のことが確認できる。
以下の内容はChakra UIの各コンポーネントにデフォルトで設定されている。（上書きも可能）
* ウィンドウの幅を小さくすると、Heading要素（「Log in」の文字）が小さくなる。
* Input要素をクリックすると枠線に色が付く。
* Input要素・Button要素が角丸になっている。
* Input要素・Button要素にカーソルを合わせると色が変わる。

#### 2.3. カラーモードを変更する機能を追加する
Chakra UIで用意されている **useColorMode** というフックを使用する。（[公式ドキュメント](https://v2.chakra-ui.com/docs/styled-system/color-mode#usecolormode)）
このフックの **toggleColorModeメソッド** を呼び出すと、ライトモードとダークモードが切り替わる。

useColorMode を @chakra-ui/react からインポートし、**「Home関数」のリターン文の上** に以下のコードを追加する。
```jsx
const { toggleColorMode } = useColorMode();
```

2 で作成した「Toggle Color Modeボタン」を、以下のように修正する。
```diff_jsx
-<Button>Toggle Color Mode</Button>
+<Button onClick={toggleColorMode}>Toggle Color Mode</Button>
```

「Toggle Color Modeボタン」をクリックすると toggleColorModeメソッド が呼び出され、ライトモードとダークモードが切り替わるようになる。
![clipboard (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/45eea069-a9b2-4046-dbd6-bdd1e58c81ee.png)

この段階では、以下の色が変わることが確認できる。これらはデフォルトでダークモード時の色が設定されている。
* 背景
* Headingコンポーネント
* Inputコンポーネント
* Buttonコンポーネント

次は、ログインフォームのFlexボックスにダークモード時の色を設定していく。

カラーモードに基づくスタイルを設定するには、Chakra UIで用意されている **useColorModeValue** というフックを使用する。（[公式ドキュメント](https://v2.chakra-ui.com/docs/styled-system/color-mode#usecolormodevalue)）
useColorModeValue は第1引数にライトモード時の値、第2引数にダークモード時の値を取る。
```jsx
useColorModeValue(${ ライトモード時の値 }, ${ ダークモード時の値 })
```

useColorModeValue を @chakra-ui/react からインポートし、 **「Home関数」のリターン文の上** に以下のコードを追加する。
```jsx
const formBackGround = useColorModeValue("gray.100", "gray.700");
```

ログインフォームのFlexボックス（background属性に "gray.100" を設定しているFlexコンポーネント）を、以下のように修正する。
```diff_jsx
-<Flex direction="column" background="gray.100" p={12} rounded={6}>
+<Flex direction="column" background={formBackGround} p={12} rounded={6}>
```

「Toggle Color Modeボタン」をクリックすると、ログインフォームのFlexボックスの色も変わることが確認できる。
![clipboard (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471657/fd64174b-e383-40c2-6031-1d77877becf1.png)

これでログイン画面の完成。
<details><summary>サンプルコード</summary>

```jsx:app/page.tsx
'use client'

import { Button, Flex, Heading, Input, useColorMode, useColorModeValue } from "@chakra-ui/react";

export default function Home() {

  const { toggleColorMode } = useColorMode();
  const formBackGround = useColorModeValue("gray.100", "gray.700");

  return (
    <Flex height="100vh" alignItems="center" justifyContent="center">
      <Flex direction="column" background={formBackGround} p={12} rounded={6}>
        <Heading mb={6}>Log in</Heading>
        <Input placeholder="sample@sample.com" variant="filled" mb={3} type="email" />
        <Input placeholder="********" variant="filled" mb={6} type="password" />
        <Button mb={6} colorScheme="teal">Log in</Button>
        <Button onClick={toggleColorMode}>Toggle Color Mode</Button>
      </Flex>
    </Flex>
  )
}
```
</details>

## 参考サイト まとめ
* Chakra UI 公式ドキュメント / チュートリアル
  * [Getting Started with Next.js](https://chakra-ui.com/getting-started/nextjs-guide)
  * [チュートリアル動画](https://www.youtube.com/watch?v=wI2vqXsjsIo)
  * [Flexコンポーネント](https://chakra-ui.com/docs/components/flex)
  * [Headingコンポーネント](https://chakra-ui.com/docs/components/heading)
  * [Inputコンポーネント](https://chakra-ui.com/docs/components/input)
  * [Buttonコンポーネント](https://chakra-ui.com/docs/components/button)
  * [Style Props](https://chakra-ui.com/docs/styled-system/style-props)
  * [色のデフォルトテーマ（"gray.100"、"teal"などについて）](https://chakra-ui.com/docs/styled-system/theme#colors)
  * [useColorMode](https://chakra-ui.com/docs/styled-system/color-mode#usecolormode)
  * [useColorModeValue](https://chakra-ui.com/docs/styled-system/color-mode#usecolormodevalue)
* [JavaScript - `export default`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export)
* [CSS リファレンス](https://developer.mozilla.org/ja/docs/Web/CSS/Reference)
* [SPA（シングルページアプリケーション）](https://digitalidentity.co.jp/blog/creative/about-single-page-application.html)