Youtube動画を見ながらNext.jsの学習を進めようの記事、第三弾となります。
1回目の記事はこちら
2回目の記事はこちら
今回の対象ファイル
今回の3回目ではログインページのフォーム追加であったり、サインアップ・ログインボタンの実装をしていってます。
主に編集を加えていってるのは以下のファイル
src/app/page.tsx
src/components/forms/PatientForm.tsx
src/components/CustomFormField.tsx
src/components/SubmitButton.tsx
これに新しく、validation.tsを作成しています。
src/lib/validation.ts
コンポーネント部分の調整と、フォーム入力の際のバリデーションに関する実装、という感じですね。
フックの利用
PatientForm.tsxの編集では、フックと呼ばれるものが出てきました。
いまいち理解していなかったので、例のごとくChatGPTに質問。
useStateは状態管理に関するもので、useRouterはルーティング機能に関するものなんですね。
現在の情報、状態の更新、状態の初期値を指定することで、レンダリングするたびに更新されるというのがuseStateだと。
そしてuseRouterは
useRouter
は Next.js のフックで、ページのルーティング(URL の遷移やクエリパラメータの取得など)に関する情報やメソッドにアクセスするために使用されます。Next.js はページベースのルーティングシステムを提供しており、useRouter
はこのシステムと連携するための強力なツールです。
と書かれていますので、オブジェクトを作った上で以下メソッドを利用してページ遷移の実装をしているんですね。
この辺はWordPress(PHP)での扱いに近いなぁと思いながらコーディングを進めていきます。
フォームフィールドに関するコンポーネントの編集
フォーム入力部分については、テキスト形式(名前など)なのか、数字形式(電話番号)なのかの条件分けが必要になるので、今回はswitch文を利用して作成していきます。
const RenderField = ({field, props}: {field: any; props:CustomProps}) => {
const {fieldType, iconSrc, iconAlt, placeholder} = props;
switch (fieldType){
case FormFieldType.INPUT:
return(
<div className="flex rounded-md border border-dark-500 bg-dark-400">
{iconSrc && (
<Image
src = {iconSrc}
height = {24}
width= {24}
alt = {iconAlt || "icon"}
className = "ml-2"
/>
)}
<FormControl>
<Input
placeholder={placeholder}
{...field}
className="shad-input border-0"
/>
</FormControl>
</div>
)
case FormFieldType.PHONE_INPUT:
return(
<FormControl>
<PhoneInput
defaultCountry="JP"
placeholder = {placeholder}
international
withCountryCallingCode
value = {field.value as E164Number | undefined}
onChange={field.onChange}
className="input-phone"
/>
</FormControl>
)
default:
break;
}
}
ここで太字にしているPhoneInputというのがnpmでインストールする必要がありました。
React-phone-number-inputというものが用意されているようで、これをnpmで実行すれば使えるようになりました。
属性値には国名を入れることになりますが、日本の場合は『JP』と入力すればOK。
これを入れることで、入力フォームによくある国旗と+●●みたいなのが出てくるようになりました。
実際のフォームフィールドについて項目を追加
今回は、氏名・メールアドレス・電話番号が必要になるフォームの実装でしたので、コードはこんな感じになっています。
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 flex-1">
<section className="mb-12 space-y-4">
<h1 className=" header ">Hi there ✊</h1>
<p className="text-dark-700">schedule your first appointment.</p>
</section>
<CustomFormField
fieldType = {FormFieldType.INPUT}
control = {form.control}
name="name"
label="Full name"
placeholder = "サンプル太郎"
iconSrc = "/assets/icons/user.svg"
iconAlt = "user"
/>
<CustomFormField
fieldType = {FormFieldType.INPUT}
control = {form.control}
name="email"
label="Email"
placeholder = "sampletaro@test.com"
iconSrc = "/assets/icons/email.svg"
iconAlt = "email"
/>
<CustomFormField
fieldType = {FormFieldType.PHONE_INPUT}
control = {form.control}
name="phone"
label="Phone number"
placeholder = "01234567890"
iconSrc = "/assets/icons/phone.svg"
iconAlt = "phone"
/>
このCustomFormFieldひとつひとつが入力欄になっているわけですね。
そしてSubmitボタンを作成していくことになります。
Validationの実装
バリデーションはzodを利用して簡潔に書いていきます。
これ、すごく便利ですね。フォームのバリデーションって結構めんどいイメージでしたけど、zod利用するとかなり簡潔に記載することができました。
export const UserFormValidation = z.object({
username: z.string()
.min(2, "ユーザー名は2文字以上入力してください")
.max(50, "ユーザー名は50文字以内で入力してください"),
email: z.string().email("無効なアドレスです"),
phone: z.string().refine((phone) => /^\+\d{1,14}$/.test(phone), "無効な電話番号です")
})
動画ではエラーメッセージも英語で書いてますが、ここは自分の学習目的なので日本語で置き換えてます。
まとめ
こんな感じで、やっとこ動画の進捗が1時間を超えてきました(実際は5時間以上ある)
今のところはこんな感じ。左側のフォームが増えているのがわかります。
さぁ引き続き頑張っていきます!