見出し画像

Next.js のフォーム実装、もう 「事故」 らせない。 Server Actions × Zod で築く鉄壁の設計

バグに怯える夜にサヨナラを

「お問い合わせフォームを作ってください」

クライアントからそう言われたとき、あなたはどう感じますか?
「はい、簡単です!」と即答できるでしょうか。
それとも、一瞬だけ心の奥に重たい石が落ちるような感覚があるでしょうか。

かつての僕は、後者でした。

見た目はただの入力欄とボタン。
けれど、その裏側には無数の「落とし穴」が潜んでいることを知っているからです。
必須項目の抜け漏れ、不正なメールアドレス、サーバーエラー時の挙動、二重送信、そしてローディング中の UI 制御……。

これらを一つひとつ手作業で潰していく作業は、まるで地雷撤去のようでした。
「動くけれど、どこか不安」
そんなコードを本番環境にデプロイする夜は、正直言って生きた心地がしませんでした。

しかし、Next.js の Server Actions とスキーマ検証ライブラリ Zod に出会ってから、その景色は一変しました。

フォーム実装は「怖いもの」から、「型に守られた、堅牢なパズル」 へと進化したのです。

この記事では、僕が数々の失敗を経てたどり着いた、「もう二度と事故らせない、鉄壁のフォーム設計」 を共有します。


useEffect と API Routes の迷宮

少し前までの僕のフォーム実装は、正直言って「継ぎ接ぎだらけ」でした。

Pages Router 時代、あるいは React の `useEffect` を多用していた頃のコードを思い出すと、今でも冷や汗が出ます。

散らばるバリデーション:
クライアント側で JavaScript でチェックし、API Route 側でも同じようなチェックを書く二重管理。
修正漏れが頻発しました。

肥大化するステート:
`const [name, setName] = useState('')` ...
入力項目が増えるたびに増殖する `useState`。
そして `isLoading`, `isError`, `successMessage`...
管理しきれない状態変数たち。

型安全性の欠如:
API から返ってくるエラーレスポンスの型が曖昧で、フロントエンドで `any` で受けてしまう妥協。

結果として出来上がるのは、「動いているけれど、誰も触りたくないスパゲッティコード」でした。
仕様変更が入るたびにどこかが壊れ、バリデーションをすり抜けた不正データがデータベースに保存されてしまう——そんな「事故」が、忘れた頃にやってくるのです。

サーバーとクライアントを 「型」 で繋ぐ

転機は、Next.js App Router の本格導入と共に訪れました。

Server Actions の登場です。

これにより、フォームの送信処理を「関数」として定義し、それを直接コンポーネントから呼べるようになりました。
API エンドポイントを意識する必要がなくなり、サーバー側のロジックとクライアント側の UI がシームレスに繋がったのです。

そして、そこに Zod という最強の盾を組み合わせる。

これが、僕が見つけた「鉄壁」の正体でした。

バリデーションの一元化:
Zod スキーマを一つ定義すれば、それをサーバー側の検証にも、クライアント側の型定義にも使い回せる。

プログレッシブ・エンハンスメント:
JavaScript がオフでも最低限動作する堅牢な基盤。

型の導き:
入力値も、返却されるエラーメッセージも、すべて TypeScript の型が守ってくれる。

「あ、これなら事故りようがない」

初めてこの構成で実装し終えたとき、そう確信しました。
コード量は減っているのに、安心感は何倍にも増していたのです。

3 つのレイヤー

この(鉄壁の)設計は、大きく分けて 3 つのレイヤーで構成されています。

Definition Layer (定義層):
Zod で「正しいデータ」の形を定義する。

Action Layer (処理層):
Server Action で入力を検証し、結果(成功/失敗)を返す。

UI Layer (表示層):
`useActionState` (旧 `useFormState`) で状態を受け取り、ユーザーにフィードバックする。

この分離が、メンテナンス性と堅牢性を劇的に高めます。

では、具体的な実装コードを見ていきましょう。
ここからは、僕が実際の案件や個人開発で使い回している「テンプレート」レベルの実装パターンを公開します。

ここから先は

5,855字 / 1画像

メンバーシップ ¥ 500 /月

■メンバーシップ 15 年目フリーランス開発者のひとり戦略を支える作戦会議室です。\ 案件に追われる…

ベーシックプラン

¥500 / 月

最後まで読んでいただき、ありがとうございます。もしこの記事が「役に立った」「心に響いた」と感じたら、珈琲一杯分サポートいただけると嬉しいです。あなたの温かい応援を力に、また次の創作活動に励みます。