Rio Blog

世界のどこかでゆるく生きるITエンジニアのブログ

React Hook FormとMUIでモダンなフォームを作成する

モダンなデザインのログイン画面やユーザー登録フォームなどを実装したい場合、React Hook FormとMUIの組み合わせが候補の一つかと思います。今回はその方法、使い方について解説します。

React Hook Formとは?

React Hook Formは、Reactのライブラリの1つです。このライブラリを使用することで、フォームとそのバリデーションをシンプルかつ柔軟に実装できます。(以下、RHFと呼びます。)

(なお、バリデーションというのは、データが条件に合うかどうかを確認することです。メールアドレスの入力欄であれば、hoge@blog.comという形式になっているかどうかを確認するみたいな。)

公式ドキュメント

MUIとは?

MUIもReactのライブラリの1つで、UIコンポーネントライブラリとも呼ばれます。MUIを使用することで、簡単に美しいUIを実装することができます。

公式はこちら

実装の準備

フォームを作成する前に、諸々の準備をしましょう。

プロジェクトを作成

まず、適当なプロジェクトを作成します。

$ npx create-react-app react-lab --template typescript

ライブラリをインストール

続いて、作成したプロジェクトに移動して、ライブラリをインストールします。

$ cd react-lab

$ npm install react-hook-form

$ npm install @mui/material @emotion/react @emotion/styled

以下のコマンドでローカルサーバーを起動し...

$ npm start

http://localhost:3000/ にアクセスしてReactの画面が表示されればOKです!

フォームを実装

テキストフィールド、ラジオボタン、セレクトボックス、チェックボックスを実装し、ボタンをクリックでデータを確認します。

import { useForm } from 'react-hook-form'
import {
  Button, Checkbox, Container, FormControl, FormControlLabel, FormGroup, FormLabel, InputLabel, MenuItem, Radio, RadioGroup, Select, Stack, TextField
} from '@mui/material'

type formType = {
  name: string,
  gender: string,
  age: string,
  agreement: boolean
}

export default function App() {

  const { register, handleSubmit } = useForm<formType>()

  const submit = (data: formType) => {
    console.log(data)
  }

  return (
    <Container maxWidth="sm" sx={{ pt: 5 }}>
      <form onSubmit={handleSubmit(submit)}>
        <Stack spacing={3}>
          {/* TextField */}
          <TextField label="Name" {...register("name")} />

          {/* RadioButton */}
          <FormControl>
            <FormLabel>Gender</FormLabel>
            <RadioGroup row defaultValue={"male"}>
              <FormControlLabel value="male" control={<Radio {...register("gender")} />} label="Male" />
              <FormControlLabel value="female" control={<Radio {...register("gender")} />} label="Female" />
            </RadioGroup>
          </FormControl>

          {/* SelectBox */}
          <FormControl>
            <InputLabel>Age</InputLabel>
            <Select defaultValue={""} label="Age" {...register("age")}>
              <MenuItem value={""}><em>None</em></MenuItem>
              <MenuItem value={"10s"}>10~19</MenuItem>
              <MenuItem value={"20s"}>20~29</MenuItem>
              <MenuItem value={"30s"}>30~39</MenuItem>
            </Select>
          </FormControl>

          {/* CheckBox */}
          <FormGroup>
            <FormControlLabel control={<Checkbox {...register("agreement")} />} label="Agree to Terms and Conditions" />
          </FormGroup>

          <Button type="submit" color="primary" variant="contained">
            Submit
          </Button>
        </Stack>
      </form>
    </Container>
  )
}

以下、簡単にポイントを説明します。

// useFormからregister, handleSubmitを取り出す
const { register, handleSubmit } = useForm<formType>()

// 入力データがオブジェクトの形で取得できる
<form onSubmit={handleSubmit(submit)}></form>

// registerの引数がキーになる
<TextField label="Name" {...register("name")} />

ブラウザで確認

いい感じのフォームができました。

入力した値がそれぞれ取得できていますね。

MUIとRHFの連携の場合、<Controller>を使うべきか?

RHFとMUIを連携させる方法をブログやZennの記事で調べると、上記のように書かれていることが多いです。つまり、registerではなくControllerを使うべき、ということですね。

でも実際は、先のコードのようにラジオボタンチェックボックスでもregisterを使うことは可能です。僕としては、registerが使えるなら使い、そうでなければ<Controller>を使うという方針で実装しています。

もし「MUIとRHFを連携させるなら、コンポーネントは必ず<Controller>を使用すべき。なぜなら~~」という知見をお持ちの方がいたら、ぜひご教授くださいませ。よろしくお願いします。