概要
react-hook-formを使ってバリデーションを実装します。
実装方法はReactと同様です。
完成イメージ
バリデーション実装
react-hook-formのインストール
react-hook-formというライブラリを使って、簡単にバリデーションを追加することができます。
npm install react-hook-form
宣言
Contact.jsを編集してreact-hook-formを適用していきます。
useForm()から必要なオブジェクトを宣言します。
キーワード | 内容 |
---|---|
useForm | フォームを簡単に管理するためのカスタムフック |
register | フォームに適用したいルールをフックに登録するメソッド |
handleSubmit | バリデーションを通過したときにフォームのデータを受け取るメソッド |
formState | フォームの状態や情報をすべて持っている。そのためここではバリデーションエラーのメッセージを取得している |
import styles from '../styles/Contact.module.css';
+ import { useForm } from "react-hook-form";
export default function Contact() {
+ const {
+ register,
+ handleSubmit,
+ formState: { errors }
+ } = useForm();
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
onSubmit関数設定
送信ボタンがクリックされたときに実行されるonSubmit関数を設定します。
これは、APIにデータを送る想定で記述しています。
import styles from '../styles/Contact.module.css'
import { useForm } from "react-hook-form"
export default function Contact() {
const {
register,
handleSubmit,
formState:{errors}
} = useForm();
+ const onSubmit = (data) => {
+ const api_url = 'apiのURL';
+
+ fetch(api_url, {
+ method: "post",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: encodeURI(`name=${data.name}&email=${data.email}&body=${data.body}`)
+ })
+ .then((response) => response.json())
+ .then((result) => alert(result.message))
+ .catch((error) => alert(error.message))
+ }
const onSubmit = (data) => {
const api_url = 'apiのURL';
fetch(api_url, {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: encodeURI(`name=${data.name}&email=${data.email}&body=${data.body}`)
})
.then((response) => response.json())
.then((result) => alert(result.message))
.catch((error) => alert(error.message))
}
formタグでonSubmit()関数呼び出し
フォームが送信されると、作成した関数onSubmit()関数を呼び出すようにformタグにonSubmitを設定します。
- <form>
+ <form onSubmit={handleSubmit(onSubmit)}>
props追加
nameとemail、bodyフィールドに{...register(...)}というpropを追加します。
registerの中では、required属性とpattern属性、maxLength属性を指定します。
この2つにより、フィールドが正しくない場合にエラーを表示することができます。
それぞれの記述するとこのようになります。
<form onSubmit={handleSubmit(onSubmit)}>
<div className={styles.form_group}>
<label>お名前</label>
<input type="text" id="name" {...register("name", { required: "お名前は必須です。" })} />
<span className={styles.form_error} id="name_error">お名前は必須です。</span>
</div>
<div className={styles.form_group}>
<label>email</label>
<input type="email" id="email" {...register("email", {
required: "emailは必須です。",
pattern: {
value: /^[a-z0-9.]+@[a-z]+\.[a-z]+$/,
message: "emailの形式で入力してください。"
}
})} />
<span className={styles.form_error} id="email_error">emailは必須かつemailの形式で入力してください。</span>
</div>
<div className={styles.form_group}>
<label>お問合せ内容</label>
<textarea id="body" rows={4} {...register("body", {
required: "お問合わせ内容は必須です。",
maxLength: {
value: 10,
message: "10文字以下で入力してください。"
}
})}></textarea>
<span className={styles.form_error} id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
</div>
<button className={styles.submit_btn} id="submit_btn">送信</button>
</form>
次に、エラーメッセージを動的に表示するようにコードを編集します。
各エラーメッセージを下記の様に{errors.name && 左の条件にマッチした場合の動作}
を使ってエラーメッセージがあれば表示するようにします。
<form onSubmit={handleSubmit(onSubmit)}>
<div className={styles.form_group}>
<label>お名前</label>
<input type="text" id="name" {...register("name", { required: "お名前は必須です。" })} />
- <span className={styles.form_error}>{errors.name.message}</span>
+ {errors.name && <span className={styles.form_error}>{errors.name.message}</span>}
</div>
<div className={styles.form_group}>
<label>email</label>
<input type="email" id="email" {...register("email", {
required: "emailは必須です。",
pattern: {
value: /^[a-z0-9.]+@[a-z]+\.[a-z]+$/,
message: "emailの形式で入力してください。"
}
})} />
- <span className={styles.form_error} id="email_error">emailは必須かつemailの形式で入力してください。</span>
+ {errors.email && <span className={styles.form_error}>{errors.email.message}</span>}
</div>
<div className={styles.form_group}>
<label>お問合せ内容</label>
<textarea id="body" rows={4} {...register("body", {
required: "お問合わせ内容は必須です。",
maxLength: {
value: 10,
message: "10文字以下で入力してください。"
}
})}></textarea>
- <span className={styles.form_error} id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
+ {errors.body && <span className={styles.form_error}>{errors.body.message}</span>}
</div>
<button className={styles.submit_btn} id="submit_btn">送信</button>
</form>
最終的なコード
最終的なコードはこのようになっています。
import styles from '../styles/Contact.module.css';
import { useForm } from "react-hook-form";
export default function Contact() {
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
const onSubmit = (data) => {
const api_url = 'apiのURL';
fetch(api_url, {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: encodeURI(`name=${data.name}&email=${data.email}&body=${data.body}`)
})
.then((response) => response.json())
.then((result) => alert(result.message))
.catch((error) => alert(error.message))
}
return (
<main className={styles.contact_form}>
<h2>お問合せ</h2>
<form onSubmit={handleSubmit(onSubmit)}>
<div className={styles.form_group}>
<label>お名前</label>
<input type="text" id="name" {...register("name", { required: "お名前は必須です。" })} />
{errors.name && <span className={styles.form_error}>{errors.name.message}</span>}
</div>
<div className={styles.form_group}>
<label>email</label>
<input type="email" id="email" {...register("email", {
required: "emailは必須です。",
pattern: {
value: /^[a-z0-9.]+@[a-z]+\.[a-z]+$/,
message: "emailの形式で入力してください。"
}
})} />
{errors.email && <span className={styles.form_error}>{errors.email.message}</span>}
</div>
<div className={styles.form_group}>
<label>お問合せ内容</label>
<textarea id="body" rows={4} {...register("body", {
required: "お問合わせ内容は必須です。",
maxLength: {
value: 10,
message: "10文字以下で入力してください。"
}
})}></textarea>
{errors.body && <span className={styles.form_error}>{errors.body.message}</span>}
</div>
<button className={styles.submit_btn} id="submit_btn">送信</button>
</form>
</main >
)
}
ビルド
package.json編集
ページを公開できるようにするため、ビルドを実行します。
まず、package.jsonを編集してビルドスクリプトを更新します。
ビルドを実行し、生成されたファイルをoutフォルダに出力するようにします。
"scripts": {
"dev": "next dev",
- "build": "next build",
+ "build": "next build && next export",
"start": "next start",
"lint": "next lint"
},
ビルドする
ターミナルでnext-websiteフォルダ内にいることを確認して下記を実行します。
npm run build
するとファイルが生成されるのがターミナルでわかります。
今回は簡単なコーポレートサイトなので静的ページのみが生成され(Statice)に○がついているのがわかります。
フォルダを確認すると.nextフォルダとoutフォルダが増えています。
.nextフォルダにビルド結果が書き出されます。
outフォルダには生成されたHTMLファイルやJSファイルが格納されます。
確認
今まではnpm run dev
で一時的にビルドををしてサーバを起動して確認していましたが、ビルドした結果をサーバを起動して確認してみます。
npm run start
ブラウザで表示される内容に変化がない(ビルドによっておかしな挙動になってない)ことを確認して完成です。