Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
React Hook Form と Zod によるフォームバリデーション
Search
SAW
November 07, 2025
Programming
83
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React Hook Form と Zod によるフォームバリデーション
フロントエンド勉強会 in 大阪 の発表資料です。
SAW
November 07, 2025
More Decks by SAW
See All by SAW
Makefile 入門
azuki
0
110
Effortless API Documentation with Scribe
azuki
0
100
Laravelで手軽にAPIドキュメントを生成する ― Scribe活用術
azuki
0
74
🪝 便利な Property Hooks を 使ってみよう 🪝
azuki
0
110
決済システム超初心者が Stripe に入門している話
azuki
0
160
PHP で form-data を POST 以外のメソッドで受け取るには?
azuki
0
97
PHP で学ぶ OAuth 入門
azuki
2
1.5k
EditorConfig を使ってみよう
azuki
1
130
Symfony でサクッと作る REST API サーバー
azuki
1
300
Other Decks in Programming
See All in Programming
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
330
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.2k
mrbgem 三角測量 開発
ogom
0
130
App Intentsのビルドプロセスを支える技術
kntkymt
0
470
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
440
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
2.6k
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
560
Java 27新機能 / Java 27 new features
kishida
2
180
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
4.4k
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
180
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
180
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
260
Featured
See All Featured
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
450
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
GitHub's CSS Performance
jonrohan
1033
470k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
How to Talk to Developers About Accessibility
jct
2
560
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
320
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
380
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
430
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
440
Balancing Empowerment & Direction
lara
6
1.3k
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
ҰൠࢀՃνέοτ ·͍Ͳνέοτ ൃചத