React+MUI v5 の 入力フォーム用のライブラリは React Hook Form の 一択
今回は React(Typescript) + MUI(v5) の フォームライブラリをどれにしようか調査しました。
入力フォーム用のライブラリ
React の入力フォーム用のライブラリをどれにするか?
2022年03月22日時点で主要なもの、だいたい以下の3点のようです。
- Formik
- React Final Form
- React Hook Form
React Hook Form に決めた経緯
まずは npm trends で比較してみます。
人気順は Formik > React Hook Form > React Final Form のようです。
1. Formik
npm trends を確認すると、一番人気があるライブラリです。
ただし、他の2つのライブラリと比較して、レンダリングが多くパフォーマンスに劣るようです。
現在あえて選択することはないかと思うのでパスします。
パフォーマンスの比較
2. React Final Form
3つの中で最も軽量なライブラリです。
レンダリングは抑えられていてパフォーマンスも良いようなのですが、あまり人気はないようです。
ホームページは、親切とはいいがたく、サンプルも少ないです。
3. React Hook Form
レンダリングが抑えられていてパフォーマンスが良いです。
Formikの次に人気があり、日本語記事もたくさんヒットします。
ホームページは、説明文は少ないですが、サンプルコードは多いです。
コードを書き比べてみた
UIフレームワークは MUI v5 を使用すると決めています。
そこで、 MUI v5 を使用したコードを React Final Form と React Hook Form のそれぞれで書き比べてみました。
MUI v5 と React.useState を使った実装
まずは React Final Form と React Hook Form を使用しないで実装してみます。
トテモメンドクサイデス。
import React from 'react'
import { Stack, TextField, Button } from '@mui/material'
export function InputForm() {
const [name, setName] = React.useState('')
const [hasNameError, setHasNameError] = React.useState(false)
const inputName = React.useCallback(
(event) => {
const inputValue = event.target.value
const isEmpty = inputValue === ''
setName(inputValue)
setHasNameError(isEmpty)
},
[setName, setHasNameError]
)
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const isEmptyName = name === ''
if (isEmptyName) {
setHasNameError(true)
}
console.log(`Sybmit Name: ${name}`)
}
return (
<Stack component="form" noValidate onSubmit={handleSubmit} spacing={2} sx={{ m: 2, width: '25ch' }}>
<TextField
type="text"
label="名前"
required
value={name}
error={hasNameError}
onChange={inputName}
helperText={hasNameError ? '名前を入力してください。' : ''}
/>
<Button variant="contained" type="submit">
送信する
</Button>
</Stack>
)
}
MUI v5 と React Final Form を使った実装
つづいて MUI v5 と React Final Form を使って実装します。
React Final Form のインストール
npm install final-form react-final-form
サンプルコードです。
ホームページのサンプルコードだけでは書き方がわかりませんでした。
検索でも情報があまりヒットせず、書き方を調べるのに時間がかかりました。
react-final-form の Fieldコンポーネントの render に @mui/material のTextField を指定するような書き方をするようです。
個人的な感想ですが、あまり直観的な書き方ではないと感じました。
import { Form, Field } from 'react-final-form'
import { Stack, TextField, Button } from '@mui/material'
type Values = {
name: string
}
export function InputReactFinalForm() {
const onSubmit = (values: Values) => {
console.log(`onSubmit:${values.name}`)
}
const validateName = (value: string) => {
if (!value) {
return '名前を入力してください。'
}
return undefined
}
return (
<Form
onSubmit={onSubmit}
initialValues={{ name: 'longbridgeyuk' }}
render={({ handleSubmit }) => (
<Stack component="form" noValidate onSubmit={handleSubmit} spacing={2} sx={{ m: 2, width: '25ch' }}>
<Field
name="name"
validate={validateName}
render={({ input, meta }) => (
<TextField
{...input}
placeholder="名前"
label="名前"
helperText={meta.error}
error={meta.touched && !!meta.error}
/>
)}
/>
<Button variant="contained" type="submit">
送信する
</Button>
</Stack>
)}
/>
)
}
MUI v5 と React Hook Form を使った実装
つづいて MUI v5 と React Hook Form を使って実装します。
React Hook Form のインストール
npm install react-hook-form
サンプルコードです。
こちらはホームページのサンプルコードだけでサクッと実装できました。
個人的な感想として、コードもシンプルでわかりやすいと感じました。
ただし、MUI の TextField の場合は、React Hook Form がサクッとフィットしましたが、他のコンポーネントだとここまでサクッとはいかないようです。
2022/03/25 サンプルコード書き替えました。
React Hook Forms で MUIコンポーネントを簡単に扱うために用意されたラッパコンポーネントである Controller コンポーネントを使用して書くようです。
import { Stack, TextField, Button } from '@mui/material'
import { useForm, SubmitHandler, Controller } from 'react-hook-form'
type Inputs = {
name: string
}
export function InputReactHookFormTextField() {
const {
control,
handleSubmit,
formState: { errors }
} = useForm<Inputs>({
defaultValues: { name: 'longbridgeyuk' }
})
const validationRules = {
name: {
required: '名前を入力してください。',
minLength: { value: 4, message: '4文字以上で入力してください。' }
}
}
const onSubmit: SubmitHandler<Inputs> = (data: Inputs) => {
console.log(`submit: ${data.name}`)
}
return (
<Stack component="form" noValidate
onSubmit={handleSubmit(onSubmit)}
spacing={2} sx={{ m: 2, width: '25ch' }}>
<Controller
name="name"
control={control}
rules={validationRules.name}
render={({ field }) => (
<TextField
{...field}
type="text"
label="名前"
error={errors.name !== undefined}
helperText={errors.name?.message}
/>
)}
/>
<Button variant="contained" type="submit">
送信する
</Button>
</Stack>
)
}
まとめ
React Hook Form は ホームページのサンプルコードが多いので、導入しやすいと感じました。
また人気もあるので記事の量も多く、何か困ったことがあっても検索すれば解決しやすいです。
コードもシンプルで理解しやすいと思いました。
React(Typescript) + MUI(v5) であれば、React Hook Form の一択かなと思います。
Discussion