フォームの離脱を防ぐ
最終更新: 2022年02月02日
離脱を防ぐ必要性
長いフォームや長文の入力中に間違ってタブを閉じたり、ページを更新してしまうことがあります。その際に入力中のデータがすべて消失してしまったとしたらユーザーは相当なストレスを感じることになります。
ページを更新したり離れようとすることを離脱といいますが、フォーム編集中に離脱しようとしたらユーザーの確認アラートを挟むべきです。
離脱には
- ブラウザ操作による離脱(リロードやタブ、ウィンドウを閉じる)
- アプリ内の離脱(別のページに遷移する)
があり、その二つについて対策する必要があります。
実装
まずは使いまわせるよう離脱ガード用のカスタムフックを作成します。このフックの引数に true
が渡る状態で離脱しようとすると確認アラートが表示されます。
hooks/form-guard.tsximport { useRouter } from 'next/router'; import { useEffect } from 'react'; export const useFormGuard = (isDirty: boolean) => { const router = useRouter(); const message = '編集内容がリセットされます、本当にページ遷移しますか?'; const pageChangeHandler = () => { const answer = window.confirm(message); if (!answer) { throw 'routeChange aborted.'; } }; const beforeUnloadhandler = (event: BeforeUnloadEvent) => { event.preventDefault(); event.returnValue = message; }; useEffect(() => { if (isDirty) { // Next.jsのページ遷移を防ぐ router.events.on('routeChangeStart', pageChangeHandler); // ブラウザの離脱を防ぐ window.addEventListener('beforeunload', beforeUnloadhandler); return () => { router.events.off('routeChangeStart', pageChangeHandler); window.removeEventListener('beforeunload', beforeUnloadhandler); }; } }, [isDirty, router]); };
フォームコンポーネントで以下のように呼び出します。この例ではReact Hook Formを使っています。
const { reset, formState: { isDirty }, } = useForm(); useFormGuard(isDirty); const submit = () => { // 送信が成功した後に編集状態をリセットする reset(undefined, { keepValues: true, }); }
React Hook Form は登録したフォームに手が加えられたら isDirty
が true
になります。この状態で離脱しようとすると確認アラートが表示されます。送信後は reset
により isDirty
が false
になるので確認なく離脱できるようになります。