29

So I have been learning the Vue Composition API and was wondering what the difference between watchEffect and watch is. Watch says it's the same as the Vue 2 watch, so I'm guessing watchEffect is like the 2.0 of that? I'm wondering if there is any specific cases where one would have great advantages over the other like in the case of stopping the watchEffect and then reactivating it instead of using a boolean in a regular watch... or are they just basically different ways of writing the same thing.

Thanks!

Reference:

watcheffect: https://vue-composition-api-rfc.netlify.com/api.html#watcheffect

watch: https://vue-composition-api-rfc.netlify.com/api.html#watch

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Ruttyj
  • 853
  • 2
  • 11
  • 18

4 Answers4

20

What helped me to understand the difference between watch and watchEffect in Vue 3 was to think about watchEffect as computed with side-effects.

The watchEffect() hook works like the computed() hook or the computed option, but instead of returning a value, you use it to trigger side-effects.

Use watch whenever you want to trigger a side-effect when a single reactive value changes.

// Triggers whenever `user` is updated.
watch(user, () => doSomething({ user: user.value, profile: profile.value }))

Use watchEffect whenever you need to watch multiple reactive values and trigger a side-effect whenever any of them is updated.

// Triggers whenever `user` *or* `profile` is updated.
watchEffect(() => doSomething({ user: user.value, profile: profile.value }))

See: watch vs. watchEffect when to use what with Vue.js

moriartie
  • 928
  • 8
  • 9
  • This doesn't make sense. On `watchEffect` how does vue.js know to only trigger on `user` and `profile` changes? Are you sure `watchEffect` doesn't trigger on every change to every computed property? – Jamie Marshall Apr 12 '21 at 00:26
  • Yes, it triggers on every change to any reactive object inside the given callback function. `user`, and `profile` are the only two reactive objects in my example. – moriartie Apr 13 '21 at 04:35
  • 1
    `triggers on every change to any reactive object inside the given callback function`, How can an outer function know about references inside an inner function? I'm not sure you're correctly understanding what's going on here. – Jamie Marshall Apr 13 '21 at 05:00
  • Yes, I’m sure that I know what’s going on on the surface of it. I don’t know exactly how it works behind the scenes. See: https://v3.vuejs.org/guide/reactivity.html#how-vue-tracks-these-changes – moriartie Apr 14 '21 at 07:16
  • I agree understanding the internal mechanism is important. If a watchEffect calls another function which reads a number of properties, can the magic mechanism of Vuejs know what properties to watch? – Gqqnbig May 19 '21 at 06:43
  • @Gqqnbig yes, I think it can. The general idea is that all reactive objects in Vue are proxies - meaning whenever someone tries to access a property, the framework is notified of that access. The question is how the framework knows which method initiated the access and hence can track that method in order to invoke it again when the property changes. This is why any the logic that you want to re-run must be written eventually as something inside one of the `computed`, `watch`, or `watchEffect` methods. – Xinchao May 19 '21 at 08:18
  • 4
    @JamieMarshall That is exactly what the reactive system in Vue does. At a high level, the moment `watchEffect(yourMethod)` is invoked, Vue knows `yourMethod` is an effect and keeps it somewhere in a variable (imagine it is globally accessible). During the execution of `yourMethod`, whenever an reactive ref/object `X` is accessed, vue intercepts that access (because all reactive objects are proxies) and logs a dependency of form "`yourMethod` depends on `X`". Then going forward whenever X is changed again, yourMethod will be invoked again. – Xinchao May 19 '21 at 08:25
  • Why not use watchEffect() when you watch a single property? watchEffect will only trigger for the dependency inside the callback, witch can be a single property. – gagarine Jul 21 '21 at 11:02
  • 1
    @gagarine in my example you can see, that there are multiple (two) reactive values used inside of the callback. Using `watchEffect` would trigger on changes to both of those reactive values. Which might or might not be what you want. If not, use `watch`. If you only use a single reactive value in the callback, and this happens to be the value you want to watch, you can use either `watch` or `watchEffect`. That's correct. – moriartie Aug 14 '21 at 09:09
  • `watch` supports multiple sources so I'm still not sure re: differences. See https://v3.vuejs.org/api/computed-watch-api.html#watching-multiple-sources – xlm Feb 03 '22 at 22:15
14

watchEffect seems to be a simplified watch and the main differences are

  • Only accepts a function
    • watch can accept either a function or one or more reactive properties.
  • Runs immediately when defined and when reactive dependencies change
    • watch only runs when reactive dependencies change
JaredMcAteer
  • 21,688
  • 5
  • 49
  • 65
10

I would use:

  • watchEffect when I want to watch multiple reactive properties and I don't care about old values
  • watch when I want to watch one specific reactive properties and I may want old value

Note, above is what I would use them for, but may not be their only usage.

Also found in docs regarding the difference:

Compared to watchEffect, watch allows us to:

Perform the side effect lazily;
Be more specific about what state should trigger the watcher to re-run;
Access both the previous and current value of the watched state.

Source: https://composition-api.vuejs.org/api.html#watch

Liang Zhou
  • 2,055
  • 19
  • 20
9

watchEffect is something introduced in Vue3 with its composition api. The reason to have both watchEffect and watch, as I understand, is to keep the semantics of watch as close as possible to that of Vue2. The birth of watchEffect, if you are interested, can be traced back to here and here

As it stands today, watchEffect is an immediate/eager watch that uses a more concise/consistent syntax (consistent with computed):

  1. watchEffect does not accept explicit watch sources, but instead automatically figures out all the dependencies by immediately executing the callback (or effect as how it is called in the source code), similar to how computed works. Therefore watchEffect must run the effect immediately. And because of this, there is a common trap (at least I have to keep reminding myself of it constantly) when setting up watchEffect: you need to make sure that during the first execution of your watchEffect, all of the dependencies are indeed accessed. How would some dependency escape from being accessed? Watch for conditional statements.
  2. watchEffect will run its effect immediately as mentioned above.
  3. watchEffect is a deep watch. This is something I am not sure whether it is intended or not. If you use a reactive object inside your effect, any change on that object will cause the effect to rerun, even if the changed property is not the one you accessed or is nested.

If Vue 3 is designed from scratch or there is no concern of maintaining backward compatibility, I would imagine there will only be watchEffect

Xinchao
  • 2,929
  • 1
  • 24
  • 39