0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React の管理画面で「保存」を押しても保存されない → 読み込み前に押すと素の GET 送信になっていた

0
Posted at

自分用の管理画面(サーバーで描画した React のページ)で、項目を書き換えて「保存」を押しました。画面は一瞬読み込み直したように見えて、エラーも出ません。ところが一覧に戻ると何も変わっていませんでした。2回やって2回とも空振りでした。

アドレスバーを見ると、URL の後ろに入力した値が付いていました。

https://example.com/admin/items/123?name=新しい名前&status=paused

原因

フォームの保存処理は onSubmit で preventDefault() してから fetch で送る作りでした。

<form onSubmit={async (e) => {
  e.preventDefault();
  await fetch(`/api/items/${id}`, { method: "PATCH", body: new FormData(e.currentTarget) });
}}>

この onSubmit が効くのは、ブラウザで JavaScript が読み込まれて React が画面に結び付いた(ハイドレーションが終わった)あとです。それより前に押すと、HTML の <form> として素のまま送信されます。method も action も書いていないので、同じ URL への GET になり、値はクエリ文字列に付くだけでサーバーには保存されません。

私の場合は、Chrome のウィンドウが裏にあってタブが非表示(document.visibilityState === "hidden")だったため、読み込みが遅れて押す方が先になっていました。ブラウザ操作を自動化していて、画面を開いた直後に押していたのも原因です。

直し方1:押す前に React が結び付いたかを確かめる

自動化で押すなら、フォーム要素に React のプロパティが付いたのを待ってから押します(React の内部の名前なので、確認用と割り切ります)。

const ready = () =>
  Object.keys(document.querySelector("form")).some((k) => k.startsWith("__reactProps"));

直し方2:入力は React の状態に入ったかも確かめる

制御コンポーネントの入力欄は、el.value = "..." で書き換えても React の状態には入りません。ネイティブの setter を呼んでから input イベントを出します。

const el = document.querySelector('input[name="name"]');
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set;
setter.call(el, "新しい名前");
el.dispatchEvent(new Event("input", { bubbles: true }));

入力した値で表示が変わる箇所(プレビューなど)があれば、それが変わったのを見てから保存します。

直し方3:保存できたかは画面遷移ではなく一覧で見る

今回は「画面が読み込み直した=保存できた」と思い込んだのが空振りに気づけなかった理由でした。保存後は一覧や詳細を開き直して、値が変わっているかで判断します。

作る側としては、<form method="post"> にしておくか、読み込みが終わるまで保存ボタンを disabled にしておけば、GET で値が URL に出ることは防げます。

まとめ

  • サーバーで描画した React のフォームは、読み込み前に押すと素の HTML フォームとして送信される
  • method が無ければ GET になり、値は URL に付くだけで保存されない。エラーも出ない
  • 押す前に React が結び付いたかを確かめ、保存できたかは一覧で見直す

生成AI(Claude Code)に書かせて一人で会社を回している記録を note に書いています。
https://note.com/kaito_cometa

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?