-
Notifications
You must be signed in to change notification settings - Fork 441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for .once()
API
#136
Comments
I'm not entirely against adding function mittWithOnce(all) {
const inst = mitt(all);
inst.once = (type, fn) => {
inst.on(type, fn);
inst.on(type, inst.off.bind(inst, type, fn));
};
return inst;
} The problem with this, and with all of the implementations I have seen including the above two, is that const { once, off, emit } = mitt();
on('foo', foo); // register a normal handler
once('foo', foo); // ... and a "once" handler
off('foo', foo); // question: which does this remove? the "once" handler, or the normal handler?
emit('foo'); // correct - in either case we see one foo() invocation here
emit('foo'); // ... but whether this invokes foo() depends on which handler got removed |
Hmm, that's an interesting use case. And what comes to my mind is either not having |
It looks like Node just punts on this - it removes the first listener, regardless of whether it was added via const emitter = new EventTarget();
function foo() {}
emitter.addEventListener('foo', foo); // adds a listener
emitter.addEventListener('foo', foo, { once: true }); // simply ignored
emitter.removeEventListener('foo', foo); // removes the first (only) listener
emitter.dispatchEvent(new Event('foo')); // no listeners registered
emitter.addEventListener('foo', foo, { once: true }); // adds a "once" listener
emitter.addEventListener('foo', foo); // ignored (treated as duplicate)
emitter.dispatchEvent(new Event('foo')); // invokes foo(), removes the listener |
Hmm, the web APIs makes sense. Essentially it took the first option that I mention. We can take that as standard. For Node, the behaviour of deletion is then just one directional. |
I would love to see But doesn't the polyfill you have above leak? The call to |
|
My Two cents in this topic: const emitter = mitt()
emitter.once = (type, handler) {
const fn = (...args) => {
emitter.off(type, fn)
handler(args)
}
emitter.on(type, fn)
}
}
export default emitter I used this approach a few months ago on a medium-sized project and afaik it is working until now, no problems using We've even created a unit test to make sure it works. Maybe I missed a specific test or two 🤔 |
@juliovedovatto that's how I generally implement this, yep. The reason that solution wouldn't work in Mitt itself is because it becomes impossible to remove a handler added via |
@developit Can we return a new handler in once() or add the new handler as a property to the handler, so we can use emitter.off(type, handler) to remove the new handler added by once() emitter.once = (type, handler) {
const fn = (arg) => {
emitter.off(type, fn);
handler(arg);
};
emitter.on(type, fn);
// add a property to the handler
handler._ = fn;
// or
// return this handler
return fn;
} This makes it possible to remove handlers added via once() using emitter.off(type, handler). There is no need to consider how to remove the handlers added by on and once, it is entirely up to the user to decide. |
Typescirpt version import mitt, { Emitter, EventHandlerMap, EventType, Handler } from 'mitt';
export function mittWithOnce<Events extends Record<EventType, unknown>>(all?: EventHandlerMap<Events>) {
const inst = mitt(all);
inst.once = (type, fn) => {
inst.on(type, fn);
inst.on(type, inst.off.bind(inst, type, fn));
};
return inst as unknown as {
once<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
} & Emitter<Events>;
} |
@juliovedovatto |
Please please please (reiterating this in 2023) add an "official" implementation for |
I'm asking too! Thanks for the hard work! |
this package would also solve your problem |
Please please please (reiterating this in 2024) add an "official" implementation for .once() to the library. ❤️ Thanks! |
I appreciate that you're still holding out hope. Why not switch to kitbag? It has feature parity, more modern, supports broadcast channel, has your once method, and maybe best of all is actively being maintained. |
Please please please (reiterating this in 2024.7.5) add an "official" implementation for .once() to the library. ❤️ Thanks! |
Kitbag looks interesting...but looks like it is still a bit early?
|
Motivation
I believe this is quite common use-case where you have to listen for an even only once (for example, module getting
ready
). The library does not support this inherently but could easily be done with some wiring. This would open up a new use-case support as well as users of the library does not have to write boilerplates on their own.Example Usage
@developit I would love to know your opinion on this.
The text was updated successfully, but these errors were encountered: