はじめに
React Hook Formは、Yupなどのvalidation系パッケージと組み合わせて使うことができますが、複雑なバリデーションが不用な場合は、React Hook Form単体でもバリデーションを実装することができます。今回は、MUIのhelperTextにReact Hook Formで検知したバリデーションエラーを表示させる方法を紹介します。
バリデーションエラーをMUIのhelperTextに表示する
バリデーション実装の全体感
まずはシンプルに、20文字以内の入力必須のテキストフィールドと、選択必須のフィールドを作ってみます。MUIのコンポーネントを使用するため、Controllerを使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | import { Button, MenuItem, Stack, TextField } from "@mui/material"; import { VFC } from "react"; import { Controller, SubmitHandler, useForm } from "react-hook-form"; interface IceCreamType { label: string; value: string; } interface FormInput { userName: string; iceCreamType: IceCreamType; } const ices = [ { value: "chocolate", label: "チョコレート" }, { value: "strawberry", label: "ストロベリー" }, { value: "vanilla", label: "バニラ" } ]; export const ExampleForm: VFC = () => { // バリデーションエラーを表示するため、 formState: { errors }を使用する const { control, handleSubmit, formState: { errors } } = useForm<FormInput>(); const onSubmit: SubmitHandler<FormInput> = (data) => { console.log(data); }; return ( <> <form onSubmit={handleSubmit(onSubmit)}> <Stack spacing={2} padding={2}> <Controller name="userName" control={control} defaultValue="" // バリデーションルールを定義 rules={{ required: "入力してください", maxLength: { value: 20, message: "20文字以内にしてください" } }} render={({ field }) => ( <TextField {...field} label="お名前" // バリデーションエラーがあればhelperTextに表示する error={!!errors.userName} helperText={errors.userName && errors.userName.message} /> )} /> <Controller name="iceCreamType" control={control} defaultValue="" // バリデーションルールを定義 rules={{ required: "選択してください" }} render={({ field }) => ( <TextField label="アイスクリーム" {...field} select // バリデーションエラーがあればhelperTextに表示する error={!!errors.iceCreamType} helperText={errors.iceCreamType && errors.iceCreamType.message} > {ices.map((ice) => ( <MenuItem key={ice.value} value={ice.value}> {ice.label} </MenuItem> ))} </TextField> )} /> <Button type="submit" variant="contained"> 送信 </Button> </Stack> </form> </> ); }; |
上記のコード簡単に説明します。まずは、バリデーションエラーを表示するために必要なhookです。
1 2 3 4 5 6 | // バリデーションエラーを表示するため、 formState: { errors }を使用する const { control, handleSubmit, formState: { errors } } = useForm<FormInput>(); |
errorsは
FieldErrors<TFieldValues>
型となっているので、次のように、useFormで指定した型のプロパティ名でエラーを取得することができます。
1 2 | console.log(errors.userName?.message); console.log(errors.iceCreamType?.message); |
ここでいう
userName
や
iceCreamType
は、エラーが無い場合はundfinedとなるので、この仕組みを使ってMUIのhelperTextに表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <form onSubmit={handleSubmit(onSubmit)}> <Stack spacing={2} padding={2}> <Controller name="userName" control={control} defaultValue="" // バリデーションルールを定義 rules={{ required: "入力してください", maxLength: { value: 20, message: "20文字以内にしてください" } }} render={({ field }) => ( <TextField {...field} label="お名前" // バリデーションエラーがあればhelperTextに表示する error={!!errors.userName} helperText={errors.userName && errors.userName.message} /> )} /> </form> |
上記のコードで、Controllerコンポーネントのrulesに、バリデーションルールを登録していきます。用意されているバリデーションとしては、次のものがあります。
- required
- min / max
- minLength/ maxLength
- pattern
そして、TextFieldコンポーネントのerrorとhelperTextプロパティをセットすれば、バリデーションエラーが表示されるようになります。
他のフィールドに関連するバリデーション
他のフィールドに関連するバリデーションを作成するには、
validate
にチェック用関数を渡すことで、実装することができます。ここでは、メールアドレスの確認フォームを追加してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <Controller name="email" control={control} defaultValue="" // バリデーションルールを定義 rules={{ required: "入力してください" }} render={({ field }) => ( <TextField {...field} label="メールアドレス" // バリデーションエラーがあればhelperTextに表示する error={!!errors.email} helperText={errors.email && errors.email.message} /> )} /> <Controller name="emailConfirm" control={control} defaultValue="" // バリデーションルールを定義 rules={{ required: "入力してください", validate: (value) => { if (value !== getValues("email")) { return "メールアドレスが一致しません"; } } }} render={({ field }) => ( <TextField {...field} label="メールアドレスの確認" // バリデーションエラーがあればhelperTextに表示する error={!!errors.emailConfirm} helperText={errors.emailConfirm && errors.emailConfirm.message} /> )} /> |
2つめのControllerでvalidateに関数を渡しています。この時の第一引数には、入力された値が入ります。関数の中で他のパラメータを使用するには、
useForm
フックの
getValues()
を使用します。
バリデーションエラーがあれば、表示させたいメッセージをreturnすることで、
errors
にメッセージが入ります。
CodeSandbox
今回のコードをまとめたCodeSandboxを公開しています。
https://codesandbox.io/s/react-hook-form-f0mwh?file=/src/ExampleForm.tsx
さいごに
React Hook Formはフォーム実装のコードを軽減することができるので、今後も機能をキャッチアップして使っていきたいと思います!