【React / TypeScript】MUIとreact-hook-formを使ったフォームの作成

# 概要
[Material UI(MUI)](https://mui.com/?srsltid=AfmBOoqfVM901W_KaWeeloY0qOOq_6ngTTBTABjzIxYxgusNfQ9uhWKy)と[React Hook Form](https://react-hook-form.com/)を使ったフォームを私なりに作ってみたので、備忘録として残します。
ログインフォームを題材としてフォームを作ります。

# 前提
- Reactがインストールされていること
- MUIとReact Hook Formがインストールされていること
```
npm i @mui/material @emotion/react @emotion/styled react-hook-form
```

# サンプルコード（最小限）
React Hook Formが機能する必要最小限のコードです。
スタイルはつけておらず、これをもとにカスタマイズしていきます。

```typescript
"use client"
import { Button, TextField } from "@mui/material"
import React from "react"
import { SubmitHandler, useForm } from "react-hook-form"

type Input = {
  example: string
}

const page = () => {
  const { register, handleSubmit } = useForm<Input>()
  const onSubmit: SubmitHandler<Input> = (data) => console.log(data);
  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        <TextField
          id="outlined-basic"
          label="Outlined"
          {...register("example")}
        />
        <div>
          <Button type='submit' variant="contained">Contained</Button>
        </div>
      </form>
    </>
  )
}

export default page
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4017964/6c7374bc-e7a9-4db5-9dd1-8d1e972ea700.png)
入力された値はonSubmitのdataに渡されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4017964/e74d526d-7dc7-476e-9918-dfa0bdd6b3da.png)

# 完成したもの
```typescript
"use client"
import { Box, Button, Container, Paper, TextField } from "@mui/material"
import React from "react"
import { SubmitHandler, useForm } from "react-hook-form"

type Input = {
  email: string,
  password: string
}

const page = () => {
  const { register, handleSubmit } = useForm<Input>()
  const onSubmit: SubmitHandler<Input> = (data) => console.log(data);
  return (
    <>
      <Container sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }}>
        <Paper elevation={3} sx={{ width: "600px", padding: 4 }}>

          <Box sx={{ textAlign: "center", fontSize: "24px", fontWeight: "bold" }}>ログイン</Box>
          <form onSubmit={handleSubmit(onSubmit)}>
            <TextField
              fullWidth
              id="outlined-basic"
              label="Email"
              type="email"
              margin="normal"
              {...register("email")}
            />
            <TextField
              fullWidth
              id="outlined-basic"
              label="password"
              type="password"
              margin="normal"
              {...register("password")}
            />
            <div>
              <Button type='submit' variant="contained" sx={{ marginTop: "16px" }}>ログイン</Button>
            </div>
          </form>
          
        </Paper>
      </Container>
    </>
  )
}

export default page
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4017964/8884f6fd-3fa6-4c48-b36a-70b5abada35d.png)
私的にはシンプルなフォームが出来上がったかと思います。
ただ、入力されていなかった場合のエラー処理がまだ実装していません。
そこでReact Hook FormのuseFormにあるformStateを使っていきます。
また、MUIのTextFieldはエラー時のプロパティ(errorとhelperText)を用意しているようなのでこれと組み合わせて使っていきます。
```typescript
"use client"
import { Box, Button, Container, Paper, TextField } from "@mui/material"
import React from "react"
import { SubmitHandler, useForm } from "react-hook-form"

type Input = {
  email: string,
  password: string
}

const page = () => {
  const { register, handleSubmit, formState: { errors }} = useForm<Input>()
  const onSubmit: SubmitHandler<Input> = (data) => console.log(data);
  return (
    <>
      <Container sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }}>
        <Paper elevation={3} sx={{ width: "600px", padding: 4 }}>

          <Box sx={{ textAlign: "center", fontSize: "24px", fontWeight: "bold" }}>ログイン</Box>
          <form onSubmit={handleSubmit(onSubmit)}>
            <TextField
              fullWidth
              id="outlined-basic"
              label="Email"
              type="email"
              margin="normal"
              {...register("email", { required: true })}
              error={errors.email ? true : false }
              helperText={errors.email ? "Email is required" : ""}
            />

            <TextField
              fullWidth
              id="outlined-basic"
              label="Password"
              type="password"
              margin="normal"
              {...register("password", { required: true })}
              error={errors.password ? true : false }
              helperText={errors.password ? "Password is required" : ""}
            />
            <div>
              <Button type='submit' variant="contained" sx={{ marginTop: "16px" }}>ログイン</Button>
            </div>
          </form>
          
        </Paper>
      </Container>
    </>
  )
}

export default page
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4017964/5f79bbb0-e9a4-410d-a510-db22c0dc59db.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4017964/bf2eb586-587f-4cd8-bf63-710039d45582.png)

ログインボタンが押されて入力欄が空だったときはエラーが表示されるようになりました。

# まとめ
MUIとreact-hook-formを使って簡単なフォームを作ってみました。
理解の助けになっていただければ幸いです。
ただ、調べているうちにMUIとreact-hook-formを複合したライブラリがあるようで、これを試してみたいと思います。

https://www.npmjs.com/package/react-hook-form-mui?activeTab=readme

# 参考・引用
https://react-hook-form.com/get-started

https://mui.com/material-ui/react-text-field/

https://qiita.com/Yasushi-Mo/items/798f6c1b155382e44dbc