はじめに
(注)「~が解決した」みたいな記事じゃなくて、popstateイベントについてのメモです。
業務中、とある画面でブラウザボタンを押すとbfcache(ブラウザバック時に使うキャッシュ)が悪さをして、想定外の挙動をしてしまう、という状態だった
状況
A画面
①↓ ↑② ↓③
B画面
①ボタンを押して画面遷移(POST送信による遷移)
②ブラウザバックで画面遷移
③再度ボタンを押して画面遷移→①でキャッシュに保存された値でリクエストしてしまいエラー
(具体的には、楽観ロックエラー)
対応策としてのpopstateイベント
この時に②でブラウザバックで遷移後、この「ブラウザバックしたこと」を検知して、ブラウザバックしたのであれば、強制的にリロードしてしまおう、と考えました。
サンプルコードで試してみる
いくつか記事を拝見しましたが、自分の理解力が乏しく自分のやりたいように動いてくれるかわからなかったので、サンプルコードを自作して挙動を確認
A画面
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>A</title>
<script>
history.replaceState(null, null, null);
window.addEventListener('popstate', function(e) {
alert('popstate!!');
});
</script>
</head>
<body>
<h1>indexAです</h1>
<a href="./indexB.html">Bへ遷移</a>
</body>
</html>
いくつか書いてある参考記事(本記事文末)通りですが、
history.replaceState(null, null, null);
これで、この画面の履歴(history)を置き換えます。
大事なのは第3引数で、ここはhistoryに保存するurlを指定します。
nullにすると現在のurlを保存するようになります。
そして、次に同じ画面に遷移した際にhistoryを上書きします。
window.addEventListener('popstate', function(e) {
alert('popstate!!');
});
ここではブラウザバックされた際の処理を書いています。
今回は先ほどのreplaceStatusで必ずhistoryに履歴が保存されるので、必ずブラウザバックした際にこの処理を実行することになります。
popstatusはブラウザの履歴が変更された際に発火するイベント
B画面
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>B</title>
</head>
<body>
<h1>indexBです</h1>
<p>ブラウザバックしてください</p>
</body>
</html>
ただの遷移用のページです。
想定では、ここに遷移したらブラウザバックして、遷移先でalertが動く挙動です。
挙動結果
完全に想定していた挙動ではありませんでした。実際の挙動は以下の通り。
A画面・・・③
①↓ ↑②
B画面
①ボタンを押して画面遷移(POST送信による遷移)
②ブラウザバックで画面遷移・・・※ここで検知してほしかったが機能せず
③再度ブラウザバックしようとするとpopstateイベントが発火し、alertが実行
③でpopstateイベントが発火するので、今回のやりたいことは実現できなさそう。。。
結論
今回はこのpopstateを使った解決はできないと判断し、他の方法で解決しました。
とはいえ、完全にブラウザバックを禁止して単一的な遷移フローのサイトを作る場合はいいかもですね。
(あんまりユーザーライクじゃない気も、、、)
参考記事
参考にさせていただき、ありがとうございました。
https://zenn.dev/k_kudo/articles/9b3633f4beb0b2
https://yutaihara.com/archives/512
https://qiita.com/dkdkd335/items/5749cd740d876a9b88d5
https://rainbow-engine.com/javascript-popstate-trigger/
最後に
たかが1つのJSのAPIの理解に時間かけちゃいましたが、想定通りに動いてくれないとわかったので、まあよしとします。
こうやってゆっくりでも知見を広げて、JSと仲良くなれればと思います。