JavaScriptのaddEventListenerを削除する方法。reactなどの再読み込み時の注意点
※本ページはプロモーションが含まれていますReactでaddEventListenerを使って登録した関数がremoveEventListenerで削除できずに困りました。
コンポーネントが再読込される度にイベントが増えていく状態でした。
なんとか解決できましたので紹介します。
addEventListenerで登録したイベントを削除する方法
addEventListenerで登録したイベントは、removeEventListenerで解除できます。
const eventFunc = () => { // 実行したい処理 } // イベントに登録 window.addEventListener("focus", eventFunc); // イベントから削除 window.removeEventListener("focus", eventFunc);
無名関数で登録した場合は解除できません。
// 無名関数でイベントに登録 window.addEventListener("focus", () => { // 実行したい処理 }); // 同じ処理を書いても削除できない window.removeEventListener("focus", () => { // 実行したい処理 });
解除したい場合は関数を変数に入れて使います。
Reactなど、再読み込みがある場合の注意
removeEventListenerで削除できるのは、addEventListenerで登録した関数と「同じ関数」です。
「同じ名前」の関数ではありません。
僕はReactでaddEventListenerを登録していたのですが、再読込した際の処理でremoveEventListenerが効かず、コンポーネントが再読込される度にイベントが増えて行く現象に悩まされました。
コードはこんな感じのコード。
// 動かないコード const count = useCount(); const eventFunc = () => { // countを使った処理 console.log(count) } useEffect(() => { window.removeEventListener("focus", eventFunc); window.addEventListener("focus", eventFunc); }, [count]);
eventFuncは独自カスタムフックuseCountから取得したcountを使用している関数です。
countが更新される度に新しい関数を登録したかったので、removeEventListenerで削除してからaddEventListenerで登録すれば良いと考えましたが、これはうまくいきません。
removeEventListenerが削除するのは、初回読み込み時のeventFuncですが、 まだaddEventListenerに何も登録されていないので特に何もしません。
その後addEventListenerでeventFuncが登録されるので、初回読み込み時のeventFuncは普通に動きます。
2回目読み込み時、removeEventListenerが削除するのは、2回目読み込み時のeventFuncで、登録されている初回読み込み時のeventFuncは関数が別物なので削除されません。
その後、2回目読み込み時のeventFuncが登録されます。
このように、初回読み込み時のeventFuncが削除されず、2回目に読み込まれたeventFuncが新たに登録されるので、イベントには初回読み込み時のeventFuncと2回目読み込み時のeventFuncが存在し、countが更新される度に増えていくことになります。
removeEventListenerが削除するのは「関数名」ではなく、addEventListenerで登録された関数と同じ関数ということです。
名前が同じなら大丈夫だと頭の隅で思っていたのでハマりました。
解決策
countを更新するきっかけは別コンポーネントなので、removeEventListenerを含んだ関数をpropsで渡すことで解決しました。
const count = useCount(); const eventFunc = () => { // countを使った処理 console.log(count) } useEffect(() => { window.addEventListener("focus", eventFunc); }, [count]); // 登録したeventFumcを削除する関数 const removeListener = () => { window.removeEventListener("focus", eventFunc); } return( ...... )
Hogeコンポーネントで、countを更新するきっかけの処理の前でremoveListenerを実行すれば、初回読み込み時のeventFuncを削除し、countが更新されることで2回目のeventFuncが登録されるようになりました。
おわりに
removeEventListenerに登録するのは同じ関数名だと勘違いしていたことでハマりました。
countが変わっているため、名前が同じでも関数の構造自体変わっているので、別の関数ということなんですよね。
JavaScriptの仕組みをもっと理解せねば…。