SPAでフォーム送信が難しくなる本当の理由

SPAは「submit」を止めることで成立している

SPAでフォーム送信が難しくなる理由は、ReactやVueが難しいからではありません。
SPAというアーキテクチャ自体が、ブラウザ本来のフォーム送信機能を無効化して動いているからです。

つまり、SPAはフォームを「拡張」しているのではなく、いったん破壊してからJavaScriptで再実装しています。
ここを理解すると、なぜバリデーション・リダイレクト・戻るボタンなどで問題が起きるのかがはっきり見えてきます。

ブラウザのネイティブsubmitはとても高機能

まず通常のHTMLフォームの動作を整理します。

<form action="/users" method="POST">
  <input name="name">
  <button type="submit">送信</button>
</form>

ボタンを押すと、ブラウザは次の処理を自動で行います。

  • 入力値収集
  • バリデーション
  • リクエスト生成
  • ページ遷移
  • 履歴追加

JavaScriptは不要です。
さらに、Enterキー送信、フォーカス移動、オートコンプリート、アクセシビリティ支援まで含まれます。

つまりHTMLフォームは、単なるUI部品ではなくブラウザ組み込みのアプリケーション機能です。

SPAはsubmitをキャンセルしている

SPAではページ遷移を起こしてはいけません。
なぜならSPAは「単一ページ」を維持するアプリケーションだからです。

そのため、フレームワークはsubmitイベントを止めます。

form.addEventListener("submit", e => {
  e.preventDefault();
});

これがすべての始まりです。
この瞬間、ブラウザが持っていたフォーム機能は動作しなくなります。

代わりに何が起きているのか

SPAでは、送信処理をJavaScriptで書き直します。

async function onSubmit() {
  const name = input.value;
  await fetch("/api/users", {
    method: "POST",
    body: JSON.stringify({ name })
  });
}

見た目は同じ「送信ボタン」ですが、中身はまったく別の仕組みです。
ブラウザではなくアプリケーションコードが通信を担当します。

この変更により、多くの副作用が発生します。

なぜ問題が頻発するのか

ネイティブsubmitが消えると、次の機能をすべて自分で実装する必要があります。

  • 必須チェック
  • エラーメッセージ
  • 2重送信防止
  • リダイレクト
  • 履歴管理
  • 戻るボタン対応

例えばEnterキー。
通常は自動送信されますが、SPAでは反応しないことがあります。
キーボードイベントを個別に処理していないためです。

また、ブラウザのバリデーションも無効になります。

<input required>

ネイティブでは未入力時に送信できません。
しかしSPAではfetchが実行され、サーバに空データが送られることがあります。

特に壊れやすい「リダイレクト」

通常のフォーム送信では、サーバは次のレスポンスを返します。

HTTP/1.1 302 Found
Location: /complete

ブラウザが自動で遷移します。
しかしSPAではfetchがレスポンスを受け取るだけで、画面は変わりません。

そのため、次の処理を追加する必要があります。

router.push("/complete");

このとき履歴が正しく積まれないと、戻るボタンで再送信が起きるなどの問題が発生します。

なぜSSRでは問題が少ないのか

SSRではフォーム送信後にページ遷移が起きます。
つまりブラウザの標準挙動をそのまま使えます。

  • POST
  • リダイレクト
  • 新ページ表示

この一連の流れは数十年ブラウザで最適化されています。
SPAはそれをJavaScriptで再現しようとしているため、複雑になります。

よくある失敗例

実務で頻繁に起きる問題です。

  • 送信ボタン連打で多重登録
  • 戻るで再送信警告が出ない
  • オートフィルが効かない
  • IME確定前に送信される

これらはフレームワークのバグではありません。
ネイティブフォームを置き換えた副作用です。

SPAでフォームを扱うときの注意点

重要なのは「フォームを普通のUIだと思わない」ことです。

フォームは単なる入力欄ではなく、
ブラウザの通信機構と履歴機構を内包した機能です。

SPAではそれを再実装していると意識すると、設計が安定します。

どう考えると楽になるか

SPAでフォームが難しいのは、フレームワークの習熟不足ではありません。
アーキテクチャ上の必然です。

SPAはページ遷移を消し、代わりにJavaScriptで状態遷移を管理します。
フォーム送信は本来「ページ遷移を伴う通信」です。
この2つは思想が衝突します。

だから多くのモダンフレームワークは最近、ネイティブsubmitへ回帰する仕組み(Server Actionsなど)を導入し始めています。

フォームで悩んだときは、
「なぜこんなに面倒なのか」ではなく
「ブラウザが本来やっていた仕事を自分が背負っている」と考えると、設計の方向が見えやすくなります。