Next.jsを利用した問い合わせフォームに確認画面を追加する

最終更新日:

Table of contents

このチュートリアルでは、Newtの Form AppNext.js を利用して作成された問い合わせフォームに、確認画面を追加する手順を紹介します。
React Hook Form を利用して、実装します。

記事内で使用している主なソフトウェアのバージョン

  • Next.js(next): 13.5.6
  • React Hook Form(react-hook-form): 7.47.0

前提条件

  • Next.jsを利用した問い合わせフォームを作成済みであること

Next.jsを利用した問い合わせフォームの作成方法について知りたい場合は、以下のドキュメントをご確認ください。

概要

Next.jsで作成した問い合わせフォームに、入力内容の確認画面を追加します。
※ ここではスタイルについては扱いません。

実装としては、React Hook FormFormProvideruseFormContext を利用して、入力画面(パス: /contact/input)と確認画面(パス: /contact/confirm)でデータを共有します。

作成される問い合わせフォームは以下のようになります。

1. React Hook Formの準備

1-1. React Hook Formのインストール

まずは react-hook-form をインストールしておきましょう。

npm install react-hook-form
# or
yarn add react-hook-form

1-2. FormProviderで入力画面と確認画面をラップする

次に、入力画面(パス: /contact/input)と確認画面(パス: /contact/confirm)で useFormContext を利用できるよう、app/contact/layout.tsx を作成し、childrenFormProvider でラップしておきましょう。

  • 入力値の型として、FormValues を定義し、useForm にジェネリクスとして渡します。ここで送信するフォームは nameemailmessage の3つの情報を送るものとします
  • useFormmode という引数を渡しています。これはどのタイミングでバリデーションを行うか制御しています。ここでは onChange を指定し、変更のたびにバリデーションを実行します
app/contact/layout.tsx
1'use client'
2import { FormProvider, useForm } from 'react-hook-form'
3
4type FormValues = {
5  name: string
6  email: string
7  message: string
8}
9
10export default function Layout({ children }: { children: React.ReactNode }) {
11  const methods = useForm<FormValues>({
12    mode: 'onChange',
13  })
14
15  return <FormProvider {...methods}>{children}</FormProvider>
16}

2. フォームの作成

2-1. 環境変数の設定

以下のように、Form Appのエンドポイントを、環境変数で定義しているものとします。

.env.local
1NEXT_PUBLIC_NEWT_FORM_ENDPOINT=https://xxxxx.form.newt.so/v1/xxxxx

2-2. フォームの作成

app/contact/input/page.tsx を作成し、以下のように記述します。
ポイントは以下の通りです。

  • フォームの送信時に確認画面に遷移する(router.push('/contact/confirm') のところ)
  • useFormContext から register を利用して、入力内容を登録する

※ 上記のポイントを押さえていれば、フォームの項目はどのようなものでも構わないので、お好きな項目を設定してください。

app/contact/input/page.tsx
1'use client'
2import { useRouter } from 'next/navigation'
3import { useFormContext } from 'react-hook-form'
4
5export default function Page() {
6  const router = useRouter()
7  const { register, handleSubmit } = useFormContext()
8
9  const onSubmit = handleSubmit(async () => {
10    router.push('/contact/confirm')
11  })
12
13  return (
14    <>
15      <h1>Contact us</h1>
16      <form onSubmit={onSubmit}>
17        <label htmlFor="name">Name</label>
18        <input id="name" {...register('name')} />
19        <label htmlFor="email">Email</label>
20        <input id="email" {...register('email')} />
21        <label htmlFor="message">Message</label>
22        <textarea id="message" {...register('message')}></textarea>
23        <button type="submit">Confirm</button>
24      </form>
25    </>
26  )
27}

これで http://localhost:3000/contact/input にアクセスすると、以下のようなフォームが表示されます。
nextjs-form-confirm1.png

2-3. 確認画面の作成

app/contact/confirm/page.tsx を作成し、以下のように記述します。
ポイントは以下の通りです。

  • Backボタンを押した時に、入力画面に戻れるようにする(onClick={() => router.push('/contact/input')} のところ)
  • useFormContext から getValues を利用して、登録された内容を表示する

※ 上記のポイントを押さえていれば、フォームの項目はどのようなものでも構わないので、お好きな項目を設定してください。
※ 下記ではフォームの送信結果に応じて、/thanks または /error にリダイレクトしていますが、ここでは詳細は扱いません。興味のある方は、NewtとNext.jsを利用して、問い合わせフォームを作成する のチュートリアルをご確認ください。

app/contact/confirm/page.tsx
1'use client'
2import { useRouter } from 'next/navigation'
3import { useFormContext } from 'react-hook-form'
4
5export default function Page() {
6  const router = useRouter()
7  const { getValues, handleSubmit } = useFormContext()
8  const values = getValues()
9
10  const onSubmit = handleSubmit(async (data) => {
11    const formData = new FormData()
12    Object.entries(data).forEach(([key, value]) => {
13      formData.append(key, value)
14    })
15
16    try {
17      const response = await fetch(
18        process.env.NEXT_PUBLIC_NEWT_FORM_ENDPOINT ?? '',
19        {
20          method: 'POST',
21          body: formData,
22          headers: {
23            Accept: 'application/json',
24          },
25        },
26      )
27
28      if (response.ok) {
29        router.push('/thanks')
30      } else {
31        router.push('/error')
32      }
33    } catch (err) {
34      router.push('/error')
35    }
36  })
37
38  return (
39    <>
40      <h1>Please confirm your submission</h1>
41      <form onSubmit={onSubmit}>
42        <table>
43          <tbody>
44            <tr>
45              <th>Name</th>
46              <td>{values.name}</td>
47            </tr>
48            <tr>
49              <th>Email</th>
50              <td>{values.email}</td>
51            </tr>
52            <tr>
53              <th>Message</th>
54              <td>{values.message}</td>
55            </tr>
56          </tbody>
57        </table>
58        <div>
59          <button type="button" onClick={() => router.push('/contact/input')}>
60            Back
61          </button>
62          <button type="submit">Submit</button>
63        </div>
64      </form>
65    </>
66  )
67}

これで http://localhost:3000/contact/input から「Confirm」ボタンをクリックすると、以下のような確認画面が表示されます。
nextjs-form-confirm2.png

「Back」を押すと入力画面に戻り、「Submit」を押すとフォームが送信されることがわかります。

NewtMade in Newt