More than a problem this is a PoC. I'd like to test if this feature is something wanted or even if it has sense inside Vue ecosystem.
With this proposed API, Vue would have the ability to create watchers over custom objects that aren't part of a component.
The definition of this method would be something like:
Vue.watch(obj: Object, expOrFn: string | Function, cb: any, options?: Object): Function
The usage of this API would be something like:
const state = {
counter: 0
}
// Use subscriber() to unsubscribe ...
cons subscriber = Vue.watch(state, 'counter', newVal => console.log(`Counter updated ${newVal}`))
state.counter += 1
// Console output: 1
Watcher
The Watcher
object requires a Vue instance. I don't know if its mandatory for a watcher but I'd like to know if it feasible to decouple the Watcher
from the need of an instance. Checking the code I've seen the VM is only responsible for storing the watchers and bind itself into the callback functions.
This seems to be a considerable amount of work.
Other thing would be that the passed object would _need_ (Maybe it's not needed) to store its watchers somewhere. Maybe a private property (__watchers__
) inside the current object. Ideas are welcomed.
The object passed to Vue.watch
could be reactive or non-reactive. I see 2 options here:
Vue.observable
first. With this approach, the initial example won't work because the state was a plain object.const state = Vue.observable({
counter: 0
})
Vue.watch(state, 'counter', newVal => console.log(`Counter updated: ${newVal}`))
state.counter += 1
// Counter updated: 1
Vue.watch
makes your object reactive, if it isn't initially. We won't need to make it observable, because Vue.watch
make it reactive for us. This approach will mutate the original object.I didn't make an RFC because I want to check if this feature is useful and feasible before I inspect a bit more in the details of this new API.
If core maintainers think that it will be more suitable in RFCs repository, I'll write one then.
Any feedback is welcomed.
Thanks.
I'd like to mention that this behaviour is currently possible in userland with something like:
function watch(obj, expOrFn, cb, opts) {
let instance = null
if ('__watcherInstance__' in obj) {
instance = obj.__watcherInstance__
} else {
instance = obj.__watcherInstance__ = new Vue({ data: obj })
}
return instance.$watch(expOrFn, cb, opts)
}
const state = {
count: 0
}
const subscriber = createWatcher(state, 'count', count => console.log(`Counter updated ${count}`))
But this solution has its "problems":
If creating lots of Vue instances is not a problem, maybe this can be a good alternative to the proposed API (But a little hacky).
This is possible now in Vue 2.6.x using the new Vue.observable()
helper:
const shared = Vue.observable({ value: "hello" })
const vm = new Vue({
created() {
this.$watch(() => shared.value, (value) => {
console.log("value changed to:", value)
})
}
})
@sirlancelot Yes, I put an example in the very first comment.
Maybe we could call it syntactic sugar, but I think the necessity of a new Vue instance could be decoupled.
Oh I understand now. Yes, I do love Vue's reactivity system. I think using it outside of components is probably an anti-pattern though.
I think using it outside of components is probably an anti-pattern though.
Why do you consider this? Just curious.
I feel like developers should focus their efforts on bringing functionality IN to Vue through the use of components. You can get data OUT of those components through watchers. However, behavior should be isolated to the components.
When I think in features like this one I like to think in environments where you only need/want the reactive features of Vue but you are not interested in components. Reactive data is such a good feature that has benefits inside and outside components or even Vue.
Anyway, thanks for sharing your point of view @sirlancelot
I would say, use the observable api, it's there for that, watching objects outside of components. In those scenarios, you are likely to put the shared object in a file and import that shared objects at multiple places if needed.
If you have access to $watch
, then it would make sense to watch the component data (or others) not something from the outside. Keeping them separate will indeed prevent users to $watch
anything
We do plan to expose something like this in v3. There will be an RFC discussing the actual API design, and when it is finalized we will likely introduce it in v2 first.
Awesome!
Thanks, @yyx990803 & @posva
Hi really sorry to comment on this old thread, this just seems to be the only place where this subject is talked about in depth.
Just wanted to ask if this is already available now and if not what is the status of this? Or will this only be available in Vue 3.x.x? Thank you! 🙏🏻
@Jaimeloeuf You'll have this feature in 3.0 out of the box!
Most helpful comment
We do plan to expose something like this in v3. There will be an RFC discussing the actual API design, and when it is finalized we will likely introduce it in v2 first.