はじめに
業務においてReactを用いてフォームの作成をしていたところ、Reactではブラウザバック時にstateに保持していたフォームの値が消えてしまうということを知りました。
今回はその時の対策としてブラウザバック時にReactでもフォームの値を保持する方法をいくつか検討したのでまとめようと思います。
概要
通常のHTMLでは、ブラウザを戻ったり進んだりしてもフォームの値は保持されますが、Reactのstateは初期化されてしまうため、何かしらの方法でフォームの値を保持しておく必要があります。
検討1:イベントリスナーのpopstateを用いてhistoryオブジェクトに保持する
まず初めに、下記のようにイベントリスナーのpopstateイベントを用いてhistoryオブジェクトに保持することをを検討しました。
const [value, setValue] = useState<string>('');
useEffect(() => {
const handlePopState = (e: PopStateEvent) => {
setValue(e.state?.formValue || '');
};
window.addEventListener('popstate', handlePopState);
return () => {
window.removeEventListener('popstate', handlePopState);
};
}, []);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
setValue(inputValue);
window.history.pushState({ formValue: inputValue }, '');
};
しかし、実際に試してみたところ、popstateがうまく発火せず、不安定であるため、この方法は採用しませんでした。少し調べたところ、
ブラウザによってはpopstateが発火しないものもあるらしく、あまりいい方法ではなさそうです(今回はChromeで発火しなかった)。
検討2:ブラウザバック時に確認ダイアログを表示させる
下記のように、そもそも保持せず、ブラウザバックさせないという方法も検討しました。
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
const confirmationMessage = '本当にブラウザバックしますか?';
e.returnValue = confirmationMessage;
return confirmationMessage;
};
useEffect(() => {
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, []);
しかし、今回作成していたページはフォームを入力するページ、フォームの入力を確認するページとあり、確認ページからのブラウザバックには対応できないため見送りとしました。
検討3:localStorageを使って保持する
下記のようにlocalStorageを用いた方法も検討しました。
const [value, setValue] = useState<string>(localStorage.getItem('formValue') || '');
useEffect(() => {
localStorage.setItem('formValue', value);
}, [value]);
// 不要になったlocalStorageの値を消すための何か
// 不要になったlocalStorageの値を消すための何か
// 不要になったlocalStorageの値を消すための何か
しかし、あるタイミングで不要になったlocalStorageの値を削除するロジックを組み込む必要があり、そのタイミングが複雑であったため採用しませんでした。
検討4:sessionStorageを使って保持する
localStorageでは不要になった値が残ってしまうこと、削除するタイミングが困難であるということが課題でした。
それならばと、セッション単位で値を保持するsessionStorageを用いた方法も検討しました。
const [value, setValue] = useState<string>(sessionStorage.getItem('formValue') || '');
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
setValue(inputValue);
sessionStorage.setItem('formValue', inputValue);
};
この方法ならば削除するロジックは必要なく、セッションが切れれば値は削除されるので、この方法を採用することになりました。
最後に
今回のケースでは、通常のHTMLに似た挙動を目指していたのでsessionStorageを利用する方法が最適でした。
しかし、多種多様なケースがありますので、今回採用を見送った方法が最適な方法の可能性もありそうですね。いい学習になりました。
ご覧いただきありがとうございました!