LoginSignup
1
1

Next.jsで簡易コーポレートサイトを作成する #3 -バリデーションとビルド編-

Last updated at Posted at 2023-03-13

概要

react-hook-formを使ってバリデーションを実装します。
実装方法はReactと同様です。

完成イメージ

000001.jpg 000010.jpg

バリデーション実装

react-hook-formのインストール

react-hook-formというライブラリを使って、簡単にバリデーションを追加することができます。

npm install react-hook-form

宣言

Contact.jsを編集してreact-hook-formを適用していきます。
useForm()から必要なオブジェクトを宣言します。

キーワード 内容
useForm フォームを簡単に管理するためのカスタムフック
register フォームに適用したいルールをフックに登録するメソッド
handleSubmit バリデーションを通過したときにフォームのデータを受け取るメソッド
formState フォームの状態や情報をすべて持っている。そのためここではバリデーションエラーのメッセージを取得している
contact.js
    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にデータを送る想定で記述しています。

contact.js
    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を設定します。

contact.js
-      <form>
+      <form onSubmit={handleSubmit(onSubmit)}>

props追加

nameとemail、bodyフィールドに{...register(...)}というpropを追加します。
registerの中では、required属性とpattern属性、maxLength属性を指定します。
この2つにより、フィールドが正しくない場合にエラーを表示することができます。
それぞれの記述するとこのようになります。

contact.js(formのみ抜粋)
<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 && 左の条件にマッチした場合の動作}を使ってエラーメッセージがあれば表示するようにします。

contact.js
    <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>

最終的なコード

最終的なコードはこのようになっています。

contact.js
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 >
    )
}

保存して動作確認をします。
000020.jpg

ビルド

package.json編集

ページを公開できるようにするため、ビルドを実行します。
まず、package.jsonを編集してビルドスクリプトを更新します。
ビルドを実行し、生成されたファイルをoutフォルダに出力するようにします。

package.json
    "scripts": {
        "dev": "next dev",
-       "build": "next build",
+       "build": "next build && next export",
        "start": "next start",
        "lint": "next lint"
    },

ビルドする

ターミナルでnext-websiteフォルダ内にいることを確認して下記を実行します。

npm run build

するとファイルが生成されるのがターミナルでわかります。
今回は簡単なコーポレートサイトなので静的ページのみが生成され(Statice)に○がついているのがわかります。
000030.jpg

フォルダを確認すると.nextフォルダとoutフォルダが増えています。
.nextフォルダにビルド結果が書き出されます。
outフォルダには生成されたHTMLファイルやJSファイルが格納されます。
000040.jp

確認

今まではnpm run devで一時的にビルドををしてサーバを起動して確認していましたが、ビルドした結果をサーバを起動して確認してみます。

npm run start

ブラウザで表示される内容に変化がない(ビルドによっておかしな挙動になってない)ことを確認して完成です。

関連コンテンツ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1