Reactでフォームを扱おうとすると、毎回useState
で状態を管理して、バリデーションを書いて、エラー表示して…
これ、地味に手間。
React Hook Form(略:RHF)を使えば、それらを最小のコードで綺麗に書けるようになる。
useForm()
でフォームを初期化register()
でフォーム要素に紐づけhandleSubmit()
で送信処理errors
でエラーメッセージ管理tsx
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
tsx
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username", { required: "ユーザー名は必須です" })} />
{errors.username && <p>{errors.username.message}</p>}
<button type="submit">ログイン</button>
</form>
Zodを使えば、スキーマ(構造)とバリデーションを同時に定義できる。
tsx
const schema = z.object({
username: z.string().min(1, "ユーザー名は必須です"),
password: z.string().min(6, "6文字以上で入力してください"),
});
useForm
にスキーマを渡す:
tsx
const {
register,
handleSubmit,
formState: { errors },
} = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
});
RHFとMUIを組み合わせるときは、TextField
に{...register("name")}
を渡すだけでOK。
tsx
<TextField
label="ユーザー名"
{...register("username")}
error={!!errors.username}
helperText={errors.username?.message}
/>
error
でエラーステートを制御helperText
でエラーメッセージ表示Tailwindを使うと、柔軟なデザインをそのまま適用できる:
tsx
<input
{...register("keyword", { required: "キーワードを入力してください" })}
className="border p-2 w-full"
/>
{errors.keyword && (
<p className="text-red-500 text-sm mt-1">{errors.keyword.message}</p>
)}
今回のサンプルでは、以下をRHFで実装:
👇 サンプル:RHFログイン・検索フォームアプリ
項目 | useState手書き | React Hook Form |
---|---|---|
状態管理 | 1項目ずつ必要 | 自動でやってくれる |
バリデーション | 自前で実装 | オプションで宣言的に書ける |
エラー表示 | 自前ロジック | errors を見るだけ |
再レンダリングコスト | 多い | 少ない(Controllerベース) |
スケーラビリティ | 面倒になる | 大規模でも対応しやすい |