Next.jsを利用した問い合わせフォームに確認画面を追加する
Table of contents
このチュートリアルでは、Newtの Form App と Next.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 Form の FormProvider と useFormContext を利用して、入力画面(パス: /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
を作成し、children
を FormProvider でラップしておきましょう。
- 入力値の型として、
FormValues
を定義し、useForm にジェネリクスとして渡します。ここで送信するフォームはname
・email
・message
の3つの情報を送るものとします useForm
にmode
という引数を渡しています。これはどのタイミングでバリデーションを行うか制御しています。ここではonChange
を指定し、変更のたびにバリデーションを実行します
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のエンドポイントを、環境変数で定義しているものとします。
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
を利用して、入力内容を登録する
※ 上記のポイントを押さえていれば、フォームの項目はどのようなものでも構わないので、お好きな項目を設定してください。
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
にアクセスすると、以下のようなフォームが表示されます。
2-3. 確認画面の作成
app/contact/confirm/page.tsx
を作成し、以下のように記述します。
ポイントは以下の通りです。
- Backボタンを押した時に、入力画面に戻れるようにする(
onClick={() => router.push('/contact/input')}
のところ) - useFormContext から
getValues
を利用して、登録された内容を表示する
※ 上記のポイントを押さえていれば、フォームの項目はどのようなものでも構わないので、お好きな項目を設定してください。
※ 下記ではフォームの送信結果に応じて、/thanks
または /error
にリダイレクトしていますが、ここでは詳細は扱いません。興味のある方は、NewtとNext.jsを利用して、問い合わせフォームを作成する のチュートリアルをご確認ください。
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」ボタンをクリックすると、以下のような確認画面が表示されます。
「Back」を押すと入力画面に戻り、「Submit」を押すとフォームが送信されることがわかります。