第183章:handleSubmit で送信処理
この章では、React Hook Form(RHF)の handleSubmit を使って
「✅入力OKなら送信」「❌入力NGなら送信しない」をキレイに作れるようになります🎀
1) handleSubmit って何者?🧙♀️✨
handleSubmit は、ざっくり言うと…
- 入力チェック(バリデーション)する ✅
- OKなら
onValid(data)を呼ぶ ✅ - NGなら
onInvalid(errors)を呼ぶ(任意)❌ - ついでに
event.preventDefault()も面倒見てくれる感じ ✋📨
2) 動きのイメージ(図解)🗺️✨
3) まずは最小の型付きフォーム(必須チェック付き)🌱✨
✅ やること
registerで input を登録handleSubmit(onSubmit)を<form onSubmit=...>に渡す- 成功時だけ
onSubmit(data)が動く🎉
import { useForm, type SubmitHandler } from "react-hook-form";
type LoginFormValues = {
email: string;
password: string;
};
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<LoginFormValues>({
defaultValues: {
email: "",
password: "",
},
});
const onSubmit: SubmitHandler<LoginFormValues> = (data) => {
// ✅ バリデーションが通った時だけここに来る!
console.log("送信データ📨", data);
alert(`ログイン送信!\n${data.email}`);
};
return (
<div style={{ maxWidth: 420, margin: "40px auto", padding: 16 }}>
<h1>ログイン🍰</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<label>
メール📧
<input
type="email"
{...register("email", {
required: "メールは必須だよ💦",
})}
style={{ display: "block", width: "100%", marginTop: 6 }}
/>
</label>
{errors.email && (
<p style={{ color: "crimson" }}>{errors.email.message}</p>
)}
<label style={{ display: "block", marginTop: 12 }}>
パスワード🔑
<input
type="password"
{...register("password", {
required: "パスワードは必須だよ💦",
minLength: { value: 6, message: "6文字以上にしてね🙂" },
})}
style={{ display: "block", width: "100%", marginTop: 6 }}
/>
</label>
{errors.password && (
<p style={{ color: "crimson" }}>{errors.password.message}</p>
)}
<button type="submit" style={{ marginTop: 16, width: "100%" }}>
送信する📨✨
</button>
</form>
</div>
);
}
ここが超重要ポイント🧠✨
- ✅
onSubmit={handleSubmit(onSubmit)}←これが正解! - ❌
onSubmit={onSubmit}にしちゃうと、RHFのチェックを通らずに実行されちゃう😵💫
4) 失敗した時も受け取りたい(onInvalid)🧯⚠️
「どこがダメだったか」をまとめてログに出したい時に便利だよ〜📌
import { useForm, type SubmitHandler, type SubmitErrorHandler } from "react-hook-form";
type LoginFormValues = {
email: string;
password: string;
};
export default function App() {
const { register, handleSubmit, formState: { errors } } = useForm<LoginFormValues>();
const onValid: SubmitHandler<LoginFormValues> = (data) => {
console.log("✅OK", data);
};
const onInvalid: SubmitErrorHandler<LoginFormValues> = (formErrors) => {
console.log("❌NG", formErrors);
alert("入力にミスがあるよ〜😵 画面の赤い文字を見てね!");
};
return (
<form onSubmit={handleSubmit(onValid, onInvalid)}>
<input
placeholder="email"
{...register("email", { required: "必須だよ📧" })}
/>
{errors.email && <p>{errors.email.message}</p>}
<input
placeholder="password"
type="password"
{...register("password", { required: "必須だよ🔑" })}
/>
{errors.password && <p>{errors.password.message}</p>}
<button type="submit">送信📨</button>
</form>
);
}
5) 送信中を作る(isSubmitting)⏳✨
「送信中…」って出せると、それっぽさ爆上がり!💎 二重送信防止にもなるよ🙆♀️
import { useForm, type SubmitHandler } from "react-hook-form";
type LoginFormValues = {
email: string;
password: string;
};
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
export default function App() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<LoginFormValues>();
const onSubmit: SubmitHandler<LoginFormValues> = async (data) => {
// ✅ ここは入力OKの時だけ来る
await sleep(1200); // 通信っぽい演出📡
alert(`ログインできた体で進むよ〜😆\n${data.email}`);
};
return (
<form onSubmit={handleSubmit(onSubmit)} style={{ maxWidth: 420, margin: "40px auto" }}>
<h2>ログイン🍩</h2>
<input
placeholder="メール📧"
{...register("email", { required: "メールは必須だよ💦" })}
style={{ display: "block", width: "100%", marginBottom: 6 }}
/>
{errors.email && <p style={{ color: "crimson" }}>{errors.email.message}</p>}
<input
placeholder="パスワード🔑"
type="password"
{...register("password", { required: "パスワードは必須だよ💦" })}
style={{ display: "block", width: "100%", marginBottom: 6 }}
/>
{errors.password && <p style={{ color: "crimson" }}>{errors.password.message}</p>}
<button type="submit" disabled={isSubmitting} style={{ width: "100%", marginTop: 10 }}>
{isSubmitting ? "送信中…⏳" : "送信する📨✨"}
</button>
</form>
);
}
6) ありがちなミス集(先に潰す!)💥🐣
-
ミス①:
handleSubmitを呼ばずに渡してる- ❌
onSubmit={handleSubmit} - ✅
onSubmit={handleSubmit(onSubmit)}
- ❌
-
ミス②:ボタンが
type="button"になってる- 送信したいなら ✅
type="submit"!
- 送信したいなら ✅
-
ミス③:
register("email")の名前がズレてるtype LoginFormValuesのキーと一致させる📌
7) ミニ課題🎯✨(5〜10分)
課題A:送信成功で「フォームを初期化」🧼
useFormからresetを取り出してonSubmitの最後でreset()してみてね😊
課題B:onInvalid で一番上に「まとめエラー」🧯
onInvalidでalert("入力を確認してね!")を出すだけでもOK🙆♀️
8) 今日のまとめ🍓✨
handleSubmitは **「チェックしてOKなら実行」**の門番🛡️handleSubmit(onValid, onInvalid)で成功/失敗を分けられる🎚️isSubmittingで 送信中UI と 二重送信防止ができる⏳✅
次の第184章は「Zodってなに?」で、ここからフォームが一気にプロっぽくなるよ〜😆💖