既存のデータを編集する
登録済みのデータを編集するフォームでは、入力欄に今の値を入れた状態で描きます。このページでは、今の値の渡し方と、変更があるかどうかをisDirtyで知る方法、元に戻す操作を紹介します。
このページの内容
今の値を入力欄に入れる
今の値はdefaultValueで渡します。チェックボックスならdefaultCheckedです。値はDOMが持つので、valueで制御する必要はありません。
edit-talk-form.tsxconst title = form.field('title');
const isPublic = form.field('public');
<input defaultValue={talk.title} {...title.input} />
<input defaultChecked={talk.public} {...isPublic.input} />defaultValueは、inputを展開する前に書いてください。送信に失敗したあとは、inputに送信した値がdefaultValueとして入ります。後ろに展開したinputが前の値を上書きするので、失敗のあとは送信した値が、それ以外のときは今の値が入力欄に入ります。
落とし穴
inputのあとにdefaultValueを書くと、送信に失敗したときも今の値で上書きしてしまい、入力した内容が消えます。
変更があるかどうかを知る
form.isDirtyは、どれかの入力欄の値が描画したときから変わっていればtrueになります。行の追加や削除も変更として数えます。
値を比べる相手は、入力欄のdefaultValueです。DOMから直接読むので、キーを押すたびに再描画されることはなく、isDirtyが切り替わるときだけ描き直されます。
たとえば、変更を保存せずにページを離れようとしたときに確認を出せます。
edit-talk-form.tsxuseEffect(() => {
if (!form.isDirty) return;
const confirm = (event: BeforeUnloadEvent) => {
event.preventDefault();
};
addEventListener('beforeunload', confirm);
return () => {
removeEventListener('beforeunload', confirm);
};
}, [form.isDirty]);落とし穴
送信ボタンをdisabled={!form.isDirty}で止めるのはおすすめしません。サーバーが描いたHTMLではisDirtyがまだfalseなので、JavaScriptが届くまでボタンを押せません。また、送信に失敗したあとは送信した値が新しい初期値になるため、何も直さずに送り直すこともできなくなります。
元に戻す
type="reset"のボタンを押すと、ブラウザがすべての入力欄をdefaultValueに戻します。useFormはこのリセットに気づき、表示していたエラーを消してisDirtyをfalseに戻します。
<button type="reset">Revert</button>Server Actionが終わったあと、Reactもフォームを同じようにリセットします。送信に失敗しても入力が消えないのは、送信した値がdefaultValueとして描かれ、リセットがその値に戻すからです。
変更のある状態を試す
登録済みの登壇情報を編集するフォームです。今の値をdefaultValueで渡しています。
試してみる
- タイトルを書き換えると、「変更あり」の表示に変わります。
- 書き換えた文字を消して元のタイトルに戻すと、「変更なし」に戻ります。
- 公開のチェックを外してから「元に戻す」を押すと、値も表示も元に戻ります。