概要
npmで公開されているreact-hook-form-muiを使ってフォームを作ってみます。このライブラリは通常のreact-hook-form + MUIよりもシンプルにコーディングできるようで、npmのダウンロード数を見ると意外と利用されているような印象を持ちます。
以前にreact-hook-formとMUIを使ってフォームを作ったことがありますので、このコードと比較していきたいと思います。
前提
・Reactがインストールされていること
・MUIがインストールされていること
npm i @mui/material @emotion/react @emotion/styled
・react-hook-formとreact-hook-form-muiがインストールされていること
npm i react-hook-form react-hook-form-mui
使い方
Readmeドキュメントに記載されている通り、以下のコンポーネントが用意されていますので、これらを使ってコーディングしていくイメージかと思います。
今回の記事は一部のみ使います。
- FormContainer
- AutocompleteElement
- TextFieldElement
- SelectElement
- MultiSelectElement
- RadioButtonGroup
- CheckboxButtonGroup
- CheckboxElement
- SwitchElement
- PasswordElement
- DatePickerElement
- SliderElement
- ToggleButtonGroupElement
サンプルコード(最小限)
react-hook-form-muiが動作する必要最小限のコードです。
このコードをもとにカスタマイズをしていきます。
"use client"
import { Button } from "@mui/material"
import React from "react"
import { FormContainer, TextFieldElement } from "react-hook-form-mui"
const page = () => {
const submit = (data: object) => {
console.log(data);
}
return (
<FormContainer defaultValues={{ example: "" }} onSuccess={submit}>
<TextFieldElement name="example" label="example" required/>
<div>
<Button type='submit' variant="contained">ログイン</Button>
</div>
</FormContainer>
)
}
export default page
入力された値はsubmitメソッドの第1引数に引き渡されます。
メソッドの変数名は任意です。
比較としてreact-hook-form-muiを使わないほうのサンプルコードを以下に記載します。ほぼ同じ動作をしますが、シンプルになっていますかね
"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
オプション
MUIをもとにコンポーネントが作られているようで、sxやMUIが用意したスタイルを適用することはできるようです。
<TextFieldElement
name="example"
label="example"
variant="standard" //MUIのText Fieldより
sx={{ width: "600px" }} //スタイルの適用
/>
エラーメッセージの設定
入力されていなかった場合などのエラーメッセージはすでに用意されていますが、自分でメッセージを設定したい場合は、FormErrorProviderを使うことで設定が可能です。
"use client"
import { Button } from "@mui/material"
import React from "react"
import { FormContainer, FormErrorProvider, TextFieldElement } from "react-hook-form-mui"
const page = () => {
const submit = (data: object) => {
console.log(data);
}
const errorPrams = (error: FieldError) => {
if (error.type === 'required') {
return '入力してください。';
}
return error?.message;
}
return (
<FormErrorProvider onError={errorPrams}>
<FormContainer defaultValues={{ example: "" }} onSuccess={submit}>
<TextFieldElement
name="example"
label="example"
required
/>
<div>
<Button type='submit' variant="contained">ログイン</Button>
</div>
</FormContainer>
</FormErrorProvider>
)
}
export default page
完成したもの
"use client"
import { Box, Button, Container, Paper } from "@mui/material"
import React from "react"
import { FormContainer, PasswordElement, TextFieldElement } from "react-hook-form-mui"
const page = () => {
const submit = (data: object) => {
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>
<FormContainer defaultValues={{ email: "", password: "" }} onSuccess={submit}>
<TextFieldElement
name="email"
label="Email"
fullWidth
required
type="email"
margin="normal"
/>
<PasswordElement
name="password"
label="Password"
fullWidth
required
margin="normal"
/>
<div>
<Button type='submit' variant="contained" sx={{ marginTop: "16px" }}>ログイン</Button>
</div>
</FormContainer>
</Paper>
</Container>
</>
)
}
export default page
比較
react-hook-form-muiを使わなかった場合のコードを比較として記載します。
"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
まとめ
シンプルにコーディングできる分、エラー処理などのこだわった機能を追加するのは難しそうな印象を持ちました。
特にこだわりがなくシンプルに使いたい場合は、このライブラリは選択肢一つとしてよさそうかと思います。
参考