【Vue.js TypeScript】 removeEventListener でちょっとハマった話

Vue.js、 TypeScriptに限った話ではなく、ES6でも同様な内容ですが、
自分がそういった環境で経験したのでメモがてらに。

コンポーネントマウント時にイベント登録、破棄時にイベント解除、イベントハンドラ内でVueインスタンスのデータを更新、みたいなことをしたいとき

class Test extends Vue {
 counter: number = 0

 mounted() {
   window.addEventListener('click', this.handleWindowClick.bind(this))
 }

 beforeDestroy() {
   window.removeEventListener('click', this.handleWindowClick)
 }

 handleWindowClick() {
   this.counter += 1
 }
}

上記のような書き方だとremoveEventListenerでイベント解除できないんですね。
handleWindowClick内で this を使用しないのであればaddEventListenerの bind(this) をなくせばよいだけなのですが、上記の場合bind(this) を無くすとイベントハンドラ内での thisのスコープはvueインスタンスではなくhandleWindowClickの関数自体を参照することになってしまいます。

結論から書くと、↓このような書き方で解決できました。

class Test extends Vue {
 counter: number = 0

 mounted() {
   this.handleWindowClick = this.handleWindowClick.bind(this)
   window.addEventListener('click', this.handleWindowClick)
 }

 beforeDestroy() {
   window.removeEventListener('click', this.handleWindowClick)
 }

 handleWindowClick() {
   this.counter += 1
 }
}

this.handleWindowClick.bind(this)で返ってくる関数をイベントリスナーとして登録・解除するということですね。

最初の例だとbind(this)で返ってくる関数をイベントリスナーとして登録してるけど、解除の対象はイベントハンドラという、それぞれ別のものを指しているのでうまく行かないのは当然でした。

mounted() {
   console.log(this.handleWindowClick)
   this.handleWindowClick = this.handleWindowClick.bind(this)
   console.log(this.handleWindowClick)
}

handleWindowClick() {}

こんな感じで確認してみるとわかりやすい。

1個目のログ

ƒ handleWindowClick() {}

2個目のログ

ƒ () { [native code] }

この記事が気に入ったらサポートをしてみませんか?