Using AbortController is the best approach and requires nothing additional. Therefore this repo will be archived.
const abortController = new AbortController();
window.addEventListener("load", () => {}, abortController);
abortController.abort();A Simple wrapper for EventTarget#addEventListener returning a disposer.
Inspired by react's useEffect.
const listener = (e: PointerEvent) => {};
window.addEventListener("pointerdown", listener);
window.removeEventListener("pointerdown", listener);This pattern is not great DX in real life usage, especially when addEventListener and removeEventListener are not called within the same scope (quite common).
// Weird that listener is defined here, far away from the state it depends on
// probably causing more code coupling and weird patterns
const listener = (e: PointerEvent) => {};
function App() {
// ...
function deepState() {
window.addEventListener("pointerdown", listener);
}
}
function cleanup() {
window.removeEventListener("pointerdown", listener);
}Thinking of it, listener is (obviously) coupled to addEventListener.
It is used as an id by removeEventListener (to perform the removal), resulting in coupling.
Returning a disposer decouples this relation.
const disposers: VoidFunction[] = [];
function App() {
// ...
function deepState() {
disposers.push(window.addEventListener("pointerdown", (e) => {}));
}
}
function cleanup() {
disposers.splice(0, disposers.length).forEach((d) => d());
}This pattern saves the need to declare listeners just for the sake of being able to call removeEventListener.
It allows to inline the code resulting in better code structure.
And it is EASY!
// React
function App() {
useEffect(
() =>
window.addEventListener("pointerdown", (e) => {
console.log(dep);
}),
[dep]
);
}npm i -S easy-add-event-listenerimport addEventListener from "easy-add-event-listener";
const disposer = addEventListener(
document,
"wheel",
(e) => e satisfies WheelEvent
);
disposer();import "easy-add-event-listener/shim"; // shims globals and TS declarations
const disposer = window.addEventListener("load", () => {});
disposer();I love it! ⭐
- Install dev deps
- Run
cli.jsto generate shimmed types - Import the types into your project
- In order to patch your source files use the
--patchoption followed bypatch-package
// Setup
import addEventListener from "easy-add-event-listener";
interface MyEventTargetEvents {
foo: PointerEvent;
bar: CustomEvent;
}
class MyEventTarget extends EventTarget {}
const easy = addEventListenerFactory<MyEventTarget, MyEventTargetEvents>();
// Usage
const instance = new MyEventTarget();
const disposers = [
easy(instance, "foo", (e) => e satisfies PointerEvent),
easy(instance, "bar", (e) => e satisfies CustomEvent),
];
disposers.splice(0, disposers.length).forEach((d) => d());Typing the function was the real effort of this repo
npm run parse -- -hNo need to build.
npm version
npm publish