mobx-utils icon indicating copy to clipboard operation
mobx-utils copied to clipboard

What is a good way to prevent or warn about promise-observable mapping issues?

Open spion-h4 opened this issue 4 years ago • 2 comments

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 avatar May 21 '20 11:05 spion-h4

@spion-h4 hey what happened to your GitHub?

benjamingr avatar May 21 '20 14:05 benjamingr

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?

NaridaL avatar May 24 '20 10:05 NaridaL