Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
React Hook Form と Zod によるフォームバリデーション
Search
SAW
November 07, 2025
Programming
0
33
React Hook Form と Zod によるフォームバリデーション
フロントエンド勉強会 in 大阪 の発表資料です。
SAW
November 07, 2025
Tweet
Share
More Decks by SAW
See All by SAW
PHP で form-data を POST 以外のメソッドで受け取るには?
azuki
0
59
PHP で学ぶ OAuth 入門
azuki
2
1k
EditorConfig を使ってみよう
azuki
1
96
Symfony でサクッと作る REST API サーバー
azuki
1
220
Vite の Library Mode を使って Vue のコンポーネントをライブラリ化する
azuki
1
320
Laravel や Symfony で手っ取り早く OpenAPI のドキュメントを作成する
azuki
2
380
Provide/Inject で TypeScript の恩恵を受ける方法
azuki
3
170
GraphQL はいいぞ! ~Laravel で学ぶ GraphQL 入門~
azuki
1
400
OSS contributor への第一歩を踏み出すまでの物語
azuki
2
360
Other Decks in Programming
See All in Programming
[KNOTS 2026登壇資料]AIで拡張‧交差する プロダクト開発のプロセス および携わるメンバーの役割
hisatake
0
290
AIフル活用時代だからこそ学んでおきたい働き方の心得
shinoyu
0
140
CSC307 Lecture 06
javiergs
PRO
0
690
フロントエンド開発の勘所 -複数事業を経験して見えた判断軸の違い-
heimusu
7
2.8k
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
200
それ、本当に安全? ファイルアップロードで見落としがちなセキュリティリスクと対策
penpeen
7
3.9k
組織で育むオブザーバビリティ
ryota_hnk
0
180
プロダクトオーナーから見たSOC2 _SOC2ゆるミートアップ#2
kekekenta
0
220
AIエージェントのキホンから学ぶ「エージェンティックコーディング」実践入門
masahiro_nishimi
5
590
生成AIを使ったコードレビューで定性的に品質カバー
chiilog
1
280
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
380
Amazon Bedrockを活用したRAGの品質管理パイプライン構築
tosuri13
5
790
Featured
See All Featured
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Crafting Experiences
bethany
1
50
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.6k
Un-Boring Meetings
codingconduct
0
200
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
67
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
920
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.9k
sira's awesome portfolio website redesign presentation
elsirapls
0
150
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
7.9k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
1
440
How to Ace a Technical Interview
jacobian
281
24k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.7k
Transcript
3FBDU)PPL'PSNͱ;PEʹΑΔ ϑΥʔϜόϦσʔγϣϯ ϑϩϯτΤϯυษڧձJOେࡕ 4"8
$(whoami) w ࢯ໊Ճ౻फҰ ࡀ w ϋϯυϧωʔϜ4"8 w 9 چ5XJUUFS
!B[VLJ@FBUFS w ؔͷ*5ΤϯδχΞίϛϡχςΟͷ͔͠ ࣗশ w େࡕࡏॅɾѪग़ w ಘҙ8FCΞϓϦέʔγϣϯ։ൃ w -BSBWFM 7VF w ॴଐ༗ݶձࣾΞϦʔϓ 2 ඇৗ༻ίοΫͷதʹ খ͞ͳίοΫ͞Μೖ͍ͬͯͳ͍ ࠓͷ໎ݴ
ϑΥʔϜόϦσʔγϣϯͷඞཁੑ w ϢʔβʔͷೖྗϛεΛϑΥʔϜͷૹ৴લʹݕग़ w ೖྗඞਢͷ߲͕ೖྗ͞Ε͍ͯͳ͍ w ϝʔϧΞυϨε༣ศ൪߸ͳͲͷೖྗܗ͕ࣜਖ਼͘͠ͳ͍ w ೖྗ͞Εͨจࣈ͕ࢦఆͷൣғʹऩ·͍ͬͯͳ͍ w
Ͳͷ߲ʹΤϥʔ͕͋Δ͔Ϣʔβʔʹࢹ֮తʹೝࣝͤ͞Δ w ೖྗΤϥʔͷ͋Δ߲ʹରͯ͠Τϥʔ༰ͷϝοηʔδΛදࣔ w ϢʔβʔΤϥʔϝοηʔδͷ༰Λ֬ೝͯ͠ଈ࠲ʹೖྗΛमਖ਼Ͱ͖Δ 3
ϑΥʔϜόϦσʔγϣϯͷ࣮ݱ w ϑΥʔϜͷ֤ϑΟʔϧυͷೖྗΛͦΕͧΕνΣοΫ w ֤ϑΟʔϧυʹରͯ͠όϦσʔγϣϯϧʔϧΛఆٛͯ͠ద༻ w ֤ϑΟʔϧυͷঢ়ଶ ݕূ݁ՌͳͲ ͷཧ͕ඞཁ w
Τϥʔ͕͋ΔϑΟʔϧυʹରͯ͠ΤϥʔϝοηʔδΛదʹදࣔ w ϑΟʔϧυͷݕূ݁Ռʹج͍ͮͯΤϥʔͷදࣔɾඇදࣔͷঢ়ଶͷཧ͕ඞཁ w ϑΥʔϜͷཧϥΠϒϥϦΛར༻͢Δ͜ͱͰ࣮Λ؆ૉԽ w ϑΥʔϜͷঢ়ଶཧ w όϦσʔγϣϯͱΤϥʔϝοηʔδͷද੍ࣔޚ 4
3FBDU)PPL'PSNͷ֓ཁ
3FBDU)PPL'PSNͱ w 3FBDUͰϑΥʔϜΛ؆୯ʹѻ͑ΔΑ͏ʹ͢ΔϥΠϒϥϦ w 3FBDUͷ)PPLTʹΑͬͯϑΥʔϜͷঢ়ଶཧόϦσʔγϣϯ͕Մೳ w ϑΥʔϜͷೖྗঢ়ଶͷอ࣋ w όϦσʔγϣϯͱΤϥʔϝοηʔδͷදࣔ w
ϑΥʔϜͷૹ৴ॲཧ 6
3FBDU)PPL'PSNͷ͍ํ w ϑΥʔϜϑΟʔϧυΛ3FBDU)PPL'PSNͰཧରͱͯ͠ొ w ϑΥʔϜૹ৴࣌ͷॲཧΛࢦఆ w ϑΥʔϜͷόϦσʔγϣϯͱΤϥʔͷදࣔ 7
ϑΥʔϜσʔλͷܕఆٛ w ϑΥʔϜͰѻ͏σʔλͷܕΛఆٛ w ఆٛͨ͠ܕΛuseForm()ͷܕҾʹࢦఆՄೳ w ϑΥʔϜϑΟʔϧυͷͷܕࢦఆ͕ՄೳʹͳΔ 8 import {
useForm } from 'react-hook-form'; interface FormInput { name: string; email: string; age: number; } useForm<FormInput>();
ϑΥʔϜϑΟʔϧυͷొ w VTF'PSNIPPL͔Βregister()Λऔಘ w ϑΥʔϜϑΟʔϧυΛ3FBDU)PPL'PSNͷཧରʹొ w register()ͷҾʹೖྗϑΥʔϜʹࢦఆ͢ΔҰҙͳ໊લΛࢦఆ w useForm()ͰܕҾΛࢦఆͨ͠߹ͦͷܕͷϓϩύςΟ໊ͷΈʹ੍͞ΕΔ w
ϑΥʔϜཁૉͰregister()Λ༻ 9 const { register } = useForm<FormInput>(); return ( <form> <input {...register('name')} /> <!-- 略 --> </form> );
ϑΥʔϜͷૹ৴ॲཧ w VTF'PSNIPPL͔ΒhandleSubmit()Λऔಘ w formཁૉͷonSubmitʹhandleSubmit()Λࢦఆ w handleSubmit()ͷҾʹϑΥʔϜૹ৴࣌ʹ࣮ߦ͢ΔؔΛࢦఆ 10 const {
register, handleSubmit } = useForm(); const onSubmit = (data: FormInput) => { // 送信時の処理 }; return ( <form onSubmit={handleSubmit(onSubmit)}> <!-- 略 --> </form> );
ϑΥʔϜͷόϦσʔγϣϯ w register()ͷୈҾʹόϦσʔγϣϯϧʔϧΛࢦఆ w ඞਢ࠷খ࠷େͳͲΛࢦఆՄೳ w ΤϥʔϝοηʔδͷઃఆՄೳ 11 const {
register } = useForm<FormInput>(); return ( <form> <input {...register('name', { required: { value: true, message: '必須項目です', } })} /> <!-- 略 --> </form> );
Τϥʔϝοηʔδͷදࣔ w VTF'PSNIPPL͔ΒformStateΛऔಘͯ͠errorsΛऔΓग़͢ w errorsʹͯ͢ͷϑΥʔϜϑΟʔϧυͷΤϥʔΛแؚ w register()Ͱࢦఆͨ͠ϑΟʔϧυ໊ͱerrorsͷϓϩύςΟ໊͕ରԠ 12 const {
/* 略 */ formState: { errors } } = useForm(); return ( <form> <input {...register('name', { /* 略 */ }) /> {errors.name && (<span>{errors.name.message}</span>)} </form> );
;PEͷ֓ཁ
;PEͱ w 5ZQF4DSJQU fi STUͳόϦσʔγϣϯϥΠϒϥϦ w ܕʹج͍ͮͯεΩʔϚΛఆٛ w จࣈྻͷΑ͏ͳ୯७ͳͷ͔Βෳࡶͳߏ·ͰॊೈʹఆٛՄೳ w
ఆٛͨ͠εΩʔϚʹج͍ͮͯೖྗΛݕূ w ಛఆͷϥΠϒϥϦϑϨʔϜϫʔΫʹґଘ͠ͳ͍ w 3FBDU)PPL'PSNҎ֎ͷϑΥʔϜϥΠϒϥϦʹར༻Մೳ w 7VFͳͲͷ3FBDUҎ֎ͷϑϨʔϜϫʔΫͰར༻Մೳ 14
;PEͷ͍ํ w ;PEͰόϦσʔγϣϯ͢ΔͨΊͷεΩʔϚΛఆٛ w όϦσʔγϣϯϧʔϧͳͲ߹Θͤͯఆٛ w ఆٛͨ͠εΩʔϚΛར༻ͯ͠ೖྗΛݕূ w Τϥʔϝοηʔδͷઃఆ 15
εΩʔϚͷఆٛ w ;PEͷϝιουΛར༻ͯ͠εΩʔϚͷܕΛఆٛ w string()number()ͳͲͰجຊܕΛදݱ w object()ͰΦϒδΣΫτΛදݱ w ҾͷΦϒδΣΫτͰ͞Βʹ;PEͷεΩʔϚͷܕఆ͕ٛՄೳ w
ೖΕࢠߏͷεΩʔϚͷఆٛՄೳ w array()ͰྻΛදݱ 16 import * as z from 'zod'; const UserSchema = z.object({ name: z.string(), email: z.email(), age: z.number(), });
ೖྗͷݕূ w parse()Λར༻ͯ͠εΩʔϚͷఆ͔ٛΒೖྗΛݕূ w όϦσʔγϣϯΤϥʔ͕͋Δ߹ZodError͕UISPX͞ΕΔ w safeParse()Λར༻ͯ͠ݕূ݁ՌͷΦϒδΣΫτΛऔಘ w safeParse()ͰZodErrorUISPX͞Εͳ͍ w
ݕূ݁ՌͷΦϒδΣΫτΛฦ٫ w ฦ٫ܕݕূޭɾࣦഊͷ݁ՌͷVOJPOܕ 17 try { UserSchema.parse({ name: 'foo', age: 31 }); } catch (error) { if (error instanceof z.ZodError) { // エラー処理 } }
Τϥʔϝοηʔδͷઃఆ w εΩʔϚఆٛͷؔͷҾͰΤϥʔϝοηʔδΛࢦఆՄೳ w ZodErrorͷmessageʹࢦఆͨ͠Τϥʔϝοηʔδ͕ઃఆ͞ΕΔ 18 z.email('Invalid email address'); z.number().positive('value
should be positive');
3FBDU)PPL'PSN ;PEͷ όϦσʔγϣϯ
3FBDU)PPL'PSNͱ;PEΛΈ߹ΘͤΔ w @hookform/resolversΛΠϯετʔϧ w useForm()ͷresolverʹzodResolverΛࢦఆ w @hookform/resolvers/zod͔ΒJNQPSU w useForm()ͷܕҾʹ;PEͷεΩʔϚ͔Βੜ͞ΕΔܕΛࢦఆ w
ϑΥʔϜσʔλͷܕΛ;PEͷεΩʔϚఆٛͱ࿈ಈͤ͞Δ 20
εΩʔϚఆ͔ٛΒܕΛੜ w ;PEͷinfer<>ͰεΩʔϚఆ͔ٛΒਪ͞ΕͨܕΛੜ w infer<>ͷܕҾʹ;PEͷεΩʔϚఆٛͷܕใΛࢦఆ w typeofԋࢉࢠͰܕใΛऔಘ w ੜ͞ΕͨܕϑΥʔϜͷೖྗܕͱͯ͠ར༻Մೳ 21
const UserSchema = z.object({ name: z.string(), email: z.email(), age: z.number(), }); type UserType = z.infer<typeof UserSchema>;
3FBDU)PPL'PSNʹ;PEΛઃఆ w useForm()ͷΦϓγϣϯͷresolverʹzodResolver()Λࢦఆ w zodResolver()ͷҾʹ;PEͰఆٛͨ͠εΩʔϚΦϒδΣΫτΛࢦఆ w useForm()ͷܕҾʹ;PEͰੜͨ͠ܕΛࢦఆ w register()ͷόϦσʔγϣϯϧʔϧͷઃఆෆཁ w
;PEͷεΩʔϚఆٛʹج͍ͮͯࣗಈతʹόϦσʔγϣϯ͞ΕΔ 22 import { zodResolver } from '@hookform/resolvers/zod'; const { /* 略 */ } = useForm<UserType>({ resolver: zodResolver(UserSchema), });
/FYUKTͰར༻͢Δࡍͷҙ w 3FBDU)PPL'PSNΫϥΠΞϯταΠυͰͷΈಈ࡞ w 3FBDU)PPL'PSNΛར༻͢Δίϯϙʔωϯτʹ'use client'͕ඞཁ w αʔόʔίϯϙʔωϯτͰར༻͠Α͏ͱ͢ΔͱϏϧυΤϥʔ͕ൃੜ 23 'use
client'; import { useForm } from "react-hook-form";
·ͱΊ w 3FBDU)PPL'PSNͷجૅతͳ͍ํʹ͍ͭͯઆ໌ w ;PEʹ͍ͭͯͷجૅతͳ͍ํʹ͍ͭͯઆ໌ w 3FBDU)PPL'PSNͱ;PEΛΈ߹Θͤͨར༻ํ๏ʹ͍ͭͯઆ໌ 24
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠
એ w ϑϩϯτΤϯυΧϯϑΝϨϯεؔ։࠵༧ఆ w w ॴϚΠυʔϜ͓͓͔͞' w
ҰൠࢀՃνέοτ ·͍Ͳνέοτ ൃചத