🔗 1. マークアップにグローバルなイベントを登録する
Bad
connect() {
document.addEventListener(...);
}
Good
<div data-controller="gallery" data-action="resize@window->gallery#layout">...</div>
layout(e) {
...
}
そうする理由
イベントリスナーの追加や削除はStimulusが行うからです。
この方法が使えない場合
コントローラのコードはマークアップを前提としていますが、Stimulusコントローラをライブラリとして作成する場合はこの前提が使えないことがあります。その場合は、必ずdisconnect
でイベントリスナーを登録解除してください。
その理由
Stimulusのコントローラはconnect
やdisconnect
を任意の回数実行できます。connect
で追加されたイベントリスナーがdisconnect
でクリーンアップされないと、要素に対して複数のイベントリスナーが存在することになり、イベントリスナーのコールバックが1度ではなく複数回実行されてしまいます。
🔗 2. イベントリスナーをconnect
やdisconnect
でクリーンアップする
Bad
connect() {
document.addEventListener("click", this.findFoo.bind(this))
}
disconnect() {
document.removeEventListener("click", this.findFoo.bind(this))
}
findFoo() {
console.log(this.element.querySelector("#foo"))
}
Good
connect() {
this.boundFindFoo = this.findFoo.bind(this)
document.addEventListener("click", this.boundFindFoo)
}
disconnect() {
document.removeEventListener("click", this.boundFindFoo)
}
findFoo() {
console.log(this.element.querySelector("#foo"))
}
最初の例がよくない理由
ある関数で.bind()
が呼び出されると、新たに関数が1個作成されます。つまり.bind()
を2回呼び出せば、addEventListener
とremoveEventListener
がそれぞれ呼び出す関数の参照が異なってしまい、イベントが削除されません。
イベントリスナーの追加と削除では、同じ.bind()
関数の参照が使われるようにしてください。
参考資料
- https://stimulusjs.org/reference/actions
- Stimulus EventListener on GitHub
- Stimulus Dispatcher on GitHub
- Function Bind - MDN
概要
原著者の許諾を得て翻訳・公開いたします。