【エラー解決方法】removeEventListener() を使っても登録したイベントが削除されないときの対処法
目次
こんにちは。飯塚です。
最近、受託案件で「ログイン後しか見えない画面が、ブラウザのヒストリーバックを使うとログアウト後でも見えるのは、セキュリティ観点で好ましくない」という話が上がりました。
そこでヒストリーバックのイベント制御を調査していたのですが、途中で詰まったので記事にしました。
再現環境
| 項目 | 詳細 |
|---|---|
| OS | Windows 11 |
| 言語 | Node.js 20.12.2 |
| フレームワーク | Vue 3.5.13 |
事象: removeEventListener() を使っても登録したイベントが削除されない
WordPress のチェック回避のため、各 EventListener の後ろに意図的に半角スペースを入れています。以降同様です。ご了承ください。
onMounted(()=>{
// ヒストリーバック時にログイン画面に戻す
addEventListener ("popstate", () => {
const router = useRouter()
router.push('/login')
})
})
onUnmounted(()=>{
// ヒストリーバック時にログイン画面に戻す処理を解除
removeEventListener ("popstate", () => {
const router = useRouter()
router.push('/login')
})
})
popstate イベントを引数に指定することで、ヒストリーバックを検知させています。ヒストリーバック時にログイン画面に遷移する処理を、ログイン画面の表示後に登録、別画面遷移時(≒ログイン後)に解除させようとしています。
しかし、これでは removeEventListener() による解除はされません。
そもそもこんな冗長な書き方するな、というご指摘もあるでしょうが、開発中の試しコードでしたのでご容赦ください。
解決方法: removeEventListener() でイベントが解除される例
// ログイン画面に遷移させる関数
const toLogin = () => {
const router = useRouter()
router.push('/login')
}
onMounted(()=>{
// ヒストリーバック時にログイン画面に戻す
addEventListener ("popstate", toLogin)
})
onUnmounted(() => {
// ヒストリーバック時にログイン画面に戻す処理を解除
removeEventListener ('popstate', toLogin)
})
関数として宣言して参照を渡すと、意図した通りに登録、解除が行われます。
原因: removeEventListener() でイベントが解除されなかった理由は無名関数
原因は無名関数を使っていたためでした。MDN の addEventListener メモリーの問題の説明が分かりやすかったので、引用します。
実際、無名関数は、同じ変更のないソースコードで定義されて繰り返し呼び出されても、繰り返しの中でも同一にはなりません。
無名関数を使うと、addEventLister(), removeEventLister() のリスナーに全く同じ処理を指定したとしても参照は別になります。同一のイベントリスナーとして認識されない、というわけですね。
ちなみにオプション引数を使用する場合は、さらに条件が複雑になるのでご注意ください。
removeEventListener は EventTarget インターフェイスのメソッドで、以前に EventTarget.addEventListener() で登録されたイベントリスナーを取り外します。
取り外されるイベントリスナーはイベントの型、イベントリスナー関数そのもの、照合プロセスに影響を与えるさまざまな任意のオプションを使用して識別します。
まとめ
いかがでしょうか。
調べてみれば removeEventListener() の仕様の通りなのですが、最初にレファレンスを読むのを面倒くさがったため、時間を浪費しました。フロント開発をするなら、MDNは一通り読んでおく必要があると実感した事象でした。
今後も Vue、JavaScript、CSS を使ったフロント開発についても記事を書きますので、参考になれば幸いです。
《関連記事》
アシスタントリーダー A.Iizuka 技術の入門・まとめ系を中心に書いてます。あとで読み返したいと感じていただける記事を目指しています。
