-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Background
One of the trickiest pitfalls with Vue reactivity is the fact that adding reactivity involves wrapping an object. The original object isn't reactive, only the wrapper created with reactive({...})
.
let original = {wow: 10};
let reactive = reactive(original);
original.wow = 20; // this doesn't cause reactions
When using @VueStore
this becomes a problem if you capture this
in the constructor:
@VueStore
class AsyncStore {
value: string = null
constructor(id) {
requestData(id).then((v) => {
this.value = v; // the captured `this` refers to the original, not the reactive wrapper
});
}
}
Proposal
It would be great if we could make the original object reactive, that way the captured this
would be reactive. This is possible, but it's a tradeoff between inheritance and robustness.
Implementation
The tradeoff is between being able to extend a non-store class and being able to use this
.
Because Vue 3 uses proxies for reactivity, we can't hack the reactivity into an ordinary instance, like I do in #27. However, because Vue 3 uses proxies, we also don't have to know the data up front. New properties on a reactive object become reactive.
In principle, all we need to do for reactivity is make a constructor that returns reactive(this)
. That limits our ability to use inheritance, unfortunately, so we'll want to provide both options.
Your two options would be (as a user of the library):
- decorate with
@VueStore
and extendVueStore
, accepting the limitation that you can't extend another class - decorate with
@VueStore
and extend something else, accepting the limitation that you can't capturethis
in the constructor
In both cases @VueStore
would be responsible for creating watches from the 'on:foo'()
methods, but it would only wrap your object in a reactive proxy it doesn't already extend VueStore
.
Vue 2
See #28