Add fromEventTarget
method, to create events from side events in the unified way
#490
Replies: 6 comments 5 replies
-
How would you do removeEventListener? |
Beta Was this translation helpful? Give feedback.
-
Naive implementation sample: export function fromEventTarget(target, eventName, { mapParams: (a) => a, options } = {}) {
const event = createEvent();
const handler = (...all) => event(mapParams(...all))
if (target.addListener) target.addListener(eventName, handler, options);
else if (target.addEventListener) target.addEventListener(eventName, handler, op);
else if (target.on) target.on(eventName, handler);
else {
throw new TypeError('target passed to `fromEventTarget` should be an EventTarget or EventEmitter instance')
}
return event
} |
Beta Was this translation helpful? Give feedback.
-
Do we really need to repeat rxjs? Why not let the user take care of the subscription himself? That seems to be a bit more universal solution. type Unsubscribe = () => void
type Trigger<T> = (x: T) => void
type Subscriber<T> = (trigger: Trigger<T>) => Unsubscribe
declare const fromContinuousCallback: <T>(subscriber: Subscriber<T>) => [
resultEvent: Event<T>,
unsubscribe: Event<void>
] nodejs: const http2 = require('http2');
const client = http2.connect('https://localhost:8443', options);
const req = client.request({ ':path': '/' })
const [responseReceived, noop] = fromContinuousCallback(trigger => {
client.on('response', trigger)
});
const [dataReceived, noop] = fromContinuousCallback(trigger => {
client.on('data', trigger)
}); WebSocket: const [messageReceived, unsubscribe] = fromContinuousCallback(trigger => {
socket.on('event', trigger);
return () => socket.off('event', trigger);
}); DOM element: const buttonClicked = fromEventTarget(button, "click");
const [buttonClicked, unsubscribe] = fromContinuousCallback(trigger => {
const button = document.queryElement("#button");
button.addEventListener('click', trigger);
return () => button.removeEventListener('click', trigger);
}); setTimeout: const [anotherOneSecond, stopTimer] = fromContinuousCallback<number>(trigger => {
let i = 0
const id = setTimeout(() => trigger(i++), 1000)
return () => clearTimeout(id)
}); etc... |
Beta Was this translation helpful? Give feedback.
-
Shouldn't it be called |
Beta Was this translation helpful? Give feedback.
-
Usually, we add features that have predictable, unambiguous semantics and are difficult to implement otherwise. There are too many differences between api of libraries with this method |
Beta Was this translation helpful? Give feedback.
-
I suggest to revive this idea in a slightly different way: There is a common pattern to connect external event source to effector with scope support: const connectSocketFx = attach({
source: $socket,
effect(socket) {
socket.on("message", scopeBind(messageReceived))
}
}) More details and problems with this solution here: #666 I suggest to add new api to cover all cases with external observables - with Fork API support function fromReactiveSource<Payload, S>(config: {
source?: Store<S>,
setupOn: Clock<any>, // it is essential for Fork API support to have explicit unit to setup subscription in correct scope
setup: (scopedTrigger: (p: Payload) => Payload, sourceData?: S) => void;
}): Event<Payload> with usage like this: const $history = createStore(createBrowserHistory())
const historyUpdated = fromReactiveSource<HistoryUpdate>({
source: $history,
setupOn: [appStarted, ...],
setup: (scopedTrigger, history) => {
history.listen(scopedTrigger)
}
}) I think, it will allow to cover all cases with external subscriptions + scope support Also, i think, it might be useful to have an option to provide destruction function and trigger: const $history = createStore(createBrowserHistory())
const historyUpdated = fromReactiveSource<HistoryUpdate>({
source: $history,
setupOn: [appStarted, ...],
setup: (scopedTrigger, history) => {
const unlisten = history.listen(scopedTrigger);
return () => unlisten()
},
destroyOn: appUnmounted
}) This will allow to avoid memory leaks during SSR usage, where user would need to create separate subscription for every scope (i.e. per request) and also destroy this subscription, when request is handled and scope should be thrown away |
Beta Was this translation helpful? Give feedback.
-
What is it allows?
How:
Add method
fromEventTarget
that receives EventTarget/EventEmitter, event name, and returnsEvent
.NodeJS:
WebSocket:
socket.io-client:
ServiceWorker:
Window:
MediaQueryList:
eventemitter3:
Questions:
1. What if event listener should receive multiple parameters?
Maybe add
mapParams
2. EventTarget.addEventListener has options, how can I pass it?
Add
options
:Beta Was this translation helpful? Give feedback.
All reactions