effector icon indicating copy to clipboard operation
effector copied to clipboard

No-throw mode for `scopeBind`

Open AlexandrHoroshih opened this issue 3 years ago • 1 comments

Proposal

Add an option for scopeBind to supress its exception in case, when there is no active scope.

const maybeBinded = scopeBind(event, { safe: true })

In this case, if scopeBind called with safe: true and there is no scope, then scopeBind just returns original event or a function, which calls original event (just like when scope is found)

Use case

scopeBind is meant to be used to bind event or effect to a scope to be called later and the most common use case is to build a bridge of effector events to other reactive source, like websocket, browser api, etc

It works quite well, when used like this:

const connectSocketFx = attach({
 source: $socket,
 effect(socket) {
   socket.on("message", scopeBind(messageReceived))
 }
})

sample({
 clock: appStarted,
 target: connectSocketFx
})

// later
const scope = fork()

await allSettled(appStarted, {scope})

This way it is possible to set scope once, when app is initialized and all related subscribtions will also work in correct scope, which is also useful for tests

But if app doesn't use scopes and only needs Fork API for tests, then scopeBind usage is problematic because it throws exception, when scope is not found

And to allow usage both with and without scope users are required to write something like this:

const safeBind = (event) => {
 try {
   return scopeBind(event)
 } catch(e) {
   return event
 }
}

// later
const connectSocketFx = attach({
 source: $socket,
 effect(socket) {
   socket.on("message", safeBind(messageReceived))
 }
})

Built-in option would allow to solve these cases without custom helpers

AlexandrHoroshih avatar Apr 22 '22 15:04 AlexandrHoroshih

Good solution for hard problem 👍 I think it will greatly improve interoperability in applications

zerobias avatar Apr 22 '22 18:04 zerobias