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
76
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
79
Effortless API Documentation with Scribe
azuki
0
77
Laravelで手軽にAPIドキュメントを生成する ― Scribe活用術
azuki
0
52
🪝 便利な Property Hooks を 使ってみよう 🪝
azuki
0
89
決済システム超初心者が Stripe に入門している話
azuki
0
130
PHP で form-data を POST 以外のメソッドで受け取るには?
azuki
0
88
PHP で学ぶ OAuth 入門
azuki
2
1.4k
EditorConfig を使ってみよう
azuki
1
130
Symfony でサクッと作る REST API サーバー
azuki
1
270
Other Decks in Programming
See All in Programming
Haskell/Servantを通してWebミドルウェアを捉え直す
pizzacat83
1
630
AIが無かった頃の素敵な出会いの話
codmoninc
1
340
その節約、円になってますか?
isamumumu
1
640
OpenSpecのproposalにbrainstormingを持たせてみた
tigertora7571
1
180
5分で問診!Composer セキュリティ健康診断
codmoninc
0
770
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
180
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
930
Claude Team Plan導入・ガイド
tk3fftk
0
250
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
290
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
250
Build-to-own AI: Agentic Development for Humans
inesmontani
PRO
0
160
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
3.3k
Featured
See All Featured
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
510
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
430
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Embracing the Ebb and Flow
colly
88
5.1k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Statistics for Hackers
jakevdp
799
230k
WCS-LA-2024
lcolladotor
0
780
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Agile that works and the tools we love
rasmusluckow
331
22k
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
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
ҰൠࢀՃνέοτ ·͍Ͳνέοτ ൃചத