この記事の対象読者
- 編集画面や設定画面を作る人
- 保存前の入力内容が消える事故を減らしたい人
-
beforeunloadやフォームの変更検知をどう使うか迷っている人
本題に入る前に
業務画面では、フォームに長めの情報を入力することがあります。
問い合わせ返信文、プロフィール設定、予約内容、社内メモ、請求情報。ちょっと時間をかけて入力したあと、うっかり別ページへ移動して全部消えたら、かなり悲しいですよね。地味に心が折れます。
作る側としては「保存していないなら消えるのは自然」と思いがちです。でも使う側からすると、画面は自分の作業場所です。書きかけの内容が消えるなら、消える前に一言ほしいです。
この記事では、Reactで「未保存の変更があるか」を持ち、ページ離脱前に気づけるようにする考え方を紹介します。
変更されたかどうかを持つ
まずは、初期値と現在値が違うかを見ます。
type FormValues = {
title: string;
memo: string;
};
function isDirty(initial: FormValues, current: FormValues) {
return initial.title !== current.title || initial.memo !== current.memo;
}
小さなフォームならこれで十分です。
項目が多い場合は、React Hook Formなどのフォームライブラリが持つ isDirty を使うのもよいです。
画面内の移動で確認する
保存前にキャンセルボタンや戻るボタンを押されたとき、確認を出します。
function EditPage() {
const initialValues = { title: "予約メモ", memo: "" };
const [values, setValues] = useState(initialValues);
const dirty = isDirty(initialValues, values);
function handleCancel() {
if (dirty && !window.confirm("保存していない変更があります。移動しますか?")) {
return;
}
location.href = "/reservations";
}
return (
<form>
<input
value={values.title}
onChange={(event) => setValues({ ...values, title: event.target.value })}
/>
<textarea
value={values.memo}
onChange={(event) => setValues({ ...values, memo: event.target.value })}
/>
<button type="button" onClick={handleCancel}>戻る</button>
</form>
);
}
ポイントは、いつでも警告を出すことではありません。
未保存の変更があるときだけ聞くことです。毎回聞かれると、すぐ読み飛ばされます。
ブラウザを閉じるときの確認
ブラウザのタブを閉じる、更新する、URLを直接変えるといった操作には beforeunload が使えます。
useEffect(() => {
if (!dirty) return;
function handleBeforeUnload(event: BeforeUnloadEvent) {
event.preventDefault();
event.returnValue = "";
}
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("beforeunload", handleBeforeUnload);
};
}, [dirty]);
ブラウザによって表示文言は制御できないことがあります。なので、アプリ内の移動は自前で分かりやすく確認し、ブラウザ操作は最後の保険くらいに考えるとよいです。
自動保存という選択肢もある
毎回確認を出すより、自動保存のほうが自然な画面もあります。
たとえば、下書き、メモ、長文入力は自動保存と相性がよいです。一方で、請求情報や権限設定のように、保存のタイミングが重要なものは明示的な保存ボタンのほうが安心です。
| 画面 | 向いている方法 |
|---|---|
| メモ、下書き | 自動保存 |
| 予約作成、設定変更 | 保存ボタン |
| 権限、請求情報 | 保存ボタン + 確認 |
まとめ
フォームの未保存警告は、ユーザーを止めるためではなく、書きかけを守るためのものです。
まずは dirty を持ち、未保存の変更があるときだけ確認する。長い入力では、自動保存も選択肢に入れる。これだけで、編集画面の安心感はかなり変わります。