フォーム実装

送ってから返事が来るまで

受け口はもう作りました。今度は送る側です。送信ボタンを押してから返事が届くまでには、必ず少しの間があります。その間を放っておくと、受講生が押したかどうか分からず、二度三度と押してしまいます。

だからフォームの状態を3つに分けて持ちます。まだ送っていない、送っている最中、終わった、の3つです。

const [status, setStatus] = useState("idle");

送り始めたら sending、返事が来たら done に変えます。ボタンは disabled={status === "sending"} にしておけば、返事待ちのあいだ押せなくなります。

送信の処理

フォームの送信は onSubmit で受けます。最初にやるのは event.preventDefault() です。これを書かないと、ブラウザがページごと再読み込みしてしまい、書いた処理が最後まで走りません。

async function handleSubmit(event: React.FormEvent<HTMLFormElement>) { event.preventDefault(); setStatus("sending"); const form = new FormData(event.currentTarget); const res = await fetch("/api/contact", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ name: form.get("name"), body: form.get("body") }), }); const data = await res.json(); setStatus("done"); setMessage(data.message); }

new FormData(event.currentTarget) で、フォームの中の入力をまとめて取り出せます。入力の1つずつに useState を置かなくても、name 属性さえ付いていれば読めます。

完了の見せ方

返事が届いたら、送った人が「終わった」と分かる表示に切り替えます。入力欄をそのまま残して小さく文字を足すだけだと気付かれにくいので、完了したことをはっきり出します。

{status === "done" ? <p className="contact-done">送信が完了しました</p> : null}

断られたときは、何が足りなかったのかをそのまま見せます。res.okfalse のときにサーバーが返した error を表示すれば、受け口で書いた検証の文がそのまま案内になります。

演習

問い合わせフォームの送信処理を書いて、完了表示まで通します。

ヒント

route.ts
page.tsx
layout.tsx
プレビュー

できているか

  • 送信ボタンが出ている
  • 入れて送ると完了表示に変わる
  • 既定の送信を止めている
  • 送信中の状態を持たせている
  • 受け口に送っている