mobx-utils
mobx-utils copied to clipboard
What is a good way to prevent or warn about promise-observable mapping issues?
The fromPromise
API is great, but there is one caveat that you must be aware of to avoid endless loops. Consider the following example
@computed get featureFlagValue() {
return fromPromise(featureFlag.getValueForCurrentUser('flag')).case({
pending: () => false
fulfilled: val => val,
rejected: () => false
})
}
We would like to transform the value, but provide a default value while its loading. This can be useful for many things e.g. buttons disabled before the permission fetch arrives and other examples.
This works well, the IPromiseBasedObservable starts with the pending state and the computed has a false value.
However, once the promise resolves, the state value becomes fulfilled, which means that this computed's observable dependencies have been invalidated.
This means the whole computed will re-run, and the feature flag fetch operation will trigger again! That means going back to the pending state and completing the cycle of an endless loop.
It means you have to rewrite it like this:
@computed get featureFlag() {
return fromPromise(featureFlag.getValueForCurrentUser('flag'))
}
@computed get featureFlagValue() {
return this.featureFlag.case({
pending: () => false
fulfilled: val => val,
rejected: () => false
})
}
My question is, is there a way to prevent or at least detect this? The rule is that the computed creating the original promise based observable must not also try to access its value during that computation
@spion-h4 hey what happened to your GitHub?
Tbh @computed
seems like the wrong thing here. I guess you want a custom Observable which calls fetch
only when the onBecomeObserved
event ist triggered. I had a look if it was possible to put something like that together using mobx-utils but I didn't find anything. If you're using this pattern in a lot places it probably makes sense to make it yourself.
Maybe extending fromPromise
to allow something like fromPromise(() => createNewPromise())
, with the supplier only being called when the returned observable becomes observed makes sense?