Next.js + Netlify Forms + React Hook Formでハマった話
なぜハマったのか
Next.jsで作られているサイトでNetlify Formsを利用するサンプルが下の記事にありますが、こちらはformタグの onSubmit
属性にコールバックを登録せず、HTMLのみでフォームの送信を行う場合の解説です。
ここで厄介なのが、React Hook Formを利用している場合です。React Hook Formはformタグの onSubmit
属性に handleSubmit
関数をコールバックとして登録することで動作します。上記の記事と同様の書き方で onSubmit
属性を使ったまま書いてみましたが、Netlify側でフォームを認識してくれず、Netlify Formsとの連携がうまくできませんでした。
すでにReact Hook Formを使ってバリデーションを組んでしまっていたので、なんとかそのままの実装で安定してフォームをNetlifyに認識してもらう方法を模索しました。Netlifyがフォームを認識してくれるか否かは手元でサクッと確認できるものではないので、formタグの属性をいじりながら何度もデプロイして確認するのは骨が折れました。
解決方法
-
/public
にフォームの項目を一通り書いた静的なHTMLファイルを配置してNetlifyにフォームを認識させる - 実際のフォームのコンポーネントでは
onSubmit
属性を使ってReact Hook Formのバリデーションをかけ、AxiosやFetch APIでフォームの内容をPOSTする
/public に静的なHTMLファイルを配置
まずはフォームをNetlifyに認識してもらうために、フォームの項目を一通り持っている下記のようなHTMLファイルを作成します。
<!DOCTYPE html>
<html>
<body>
<form name="contact" netlify hidden>
<input type="text" name="name" />
<input type="text" name="email" />
<input type="text" name="subject" />
<input type="text" name="body" />
</form>
</body>
</html>
Netlifyがフォームを認識するためには netlify
という属性をformタグにつける必要があります。こちらのファイルを /public
フォルダに配置しておくと、 next build
を実行したときに /out
フォルダに配置され、デプロイの際にNetlifyから見える状態にすることができます。
コンポーネント内のフォームの書き方
次にフォームのコンポーネントの書き方です。
import { useForm } from 'react-hook-form'
export function Form() {
const { register, handleSubmit, errors } = useForm()
const onSubmit = (data) => {
data['form-name'] = 'contact'
axios.post('/', new URLSearchParams(data))
.then(postSubmission)
.catch(handleError)
}
return (
<form onSubmit={handleSubmit(onSubmit)} >
<input type="text" ref={register({ required: '必須項目です' })}>
...
<button type="submit">送信</button>
</form>
)
}
register
handleSubmit
errors
の3つをReact Hook Formの useForm
フックから取得しています。React Hook Formの使い方やインストール方法は公式ページをご覧ください。
最大のポイントは、 handleSubmit
関数の引数となるコールバック関数 onSubmit
です。この関数の引数 data
はフォームデータのオブジェクトです。こちらの関数内で、Netlifyがフォームの名前として利用する form-name
というキーを data
に追加します。 form-name
の値は /public
に配置したHTMLファイル内のformタグの name
属性の値と一致させます。最後に onSubmit
関数内でAxiosを利用してフォームデータの送信を行うようにします。
確認
Netlifyへのデプロイが完了した時点で、Netlifyの管理画面のFormsページに、上で作成したHTMLファイルのformタグの name
属性として指定した名前のフォームができていれば、HTMLファイルが正常に認識されています。実際にフォームを送信してみて、データがNetlifyに登録されるか確認してみてください。
もっと良い方法をご存じの方、ぜひぜひご指導ご教示いただけますと幸いです。
参考
Discussion