-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
How to implement an asynchronous dependency between properties #872
Comments
Regarding 2 and 3, you can use mobx-utils @computed get square() {
code here
} Unfortunately es7 is being needlessly conservative, so no async getters. You'll have to (1) is probably not fixable without switching to a custom promise implementation. |
So if I understand you correctly, I could do @computed get observableSquare() {
return fromPromise((async () => {
const value = this.value;
await sleep(500);
return value * value;
})());
}
@computed get square() {
return this.observableSquare.value;
} This would give me a property -- I just tried to set up a fiddle, but something's not working right yet. |
Seems to be working fine. Once you change the value, expect that the computed will no longer have a value property until the whole thing completes (which takes 0.5s). So the first state change of
|
You're right, it's working. :-) I just expanded the test scenario a bit to cover different timing issues (like an old promise finishing after a newer one), but it all seems to be working correctly. There's just one thing now that I'm having difficulty with: As you said (and understandably), |
Yes. this.observableSquare.case({
pending: () => this.oldValue,
rejected: e => this.oldValue,
fulfilled: v => this.oldValue = v
}) (oldValue doesn't need to be observable) Sometimes it might be a good idea to indicate in the UI that the value is stale, or that the request is in progress, so thats why fromPromise defaults to asking the user to cover all cases for the general case... |
Thank you, @spion! Introducing a new property would certainly work. However, now we've got quite some overhead for a simple asynchronous dependency. I found a package called computed-async-mobx. It's very similar to Using class NumberInfo {
@observable value = 0;
observableSquare = computedAsync({
init: 0,
fetch: async () => {
const value = this.value;
await sleep(500);
return value * value;
}
});
@computed get square() {
return this.observableSquare.value;
}
} |
First consider the following simple, synchronous code. You can run it in JSFiddle.
Property
square
depends on propertyvalue
. Changingvalue
results in a new value forsquare
, and through the magic of MobX, all updates are logged to the console.Now let's assume that calculating the square of a number is an asynchronous operation: We have to make a server request, perform a database lookup or something similar. But I still want
square
to update (asynchronously) whenevervalue
changes, and I still want to get the same log output.Here is the best solution I could come up with. You can run it in JSFiddle. It's working, but there are a number of aspects I don't like.
So here's what I don't like about my solution:
getSquare
, that is, the code before the firstawait
. In my code, I'm explicitly accessingthis.value
before theawait
. If I weren't doing this, MobX wouldn't understand thatgetSquare
depends onvalue
, so it wouldn't reliably call my autoruns. That's a source of errors, so it would be great if there was a cleaner way.autorun
in the constructor to keepsquare
updated. Given that JavaScript has no lifecycle management (destructors) for simple objects, there is no way for me to call the disposer. I'm not sure, but that probably creates some sort of memory leak within MobX.autorun
in the constructor to keepsquare
updated has another downside:square
will now be updated whenevervalue
changes, even if there is no code listening tosquare
. That goes against the rule that only relevant values should be evaluated.Is there a better way to implement an asynchronous dependency between properties?
The text was updated successfully, but these errors were encountered: