In the composite API, we can use the watch function to trigger a callback function every time the reactive state changes:
2. Listening data source type
The first parameter of watch can be a "data source" in different forms: it can be a ref (including computed properties), a reactive object, a getter function, or an array of multiple data sources:
Note that you cannot directly listen to property values of reactive objects, for example:
Here you need to use a getter function that returns the property:
3. Deep Listener
Passing a reactive object directly to watch() will implicitly create a deep listener - the callback function will be triggered on all nested changes:
In contrast, a getter function that returns a reactive object will only trigger a callback if it returns a different object:
It is also possible to explicitly add the deep option to the above example to force a deep listener:
watch() is lazy: the callback is only executed when the data source changes.
But in some scenarios, we want to execute the callback immediately when the listener is created.
Say, for example, we want to request some initial data, then re-request the data when the relevant state changes.
We can use the watchEffect function to simplify the above code.
watchEffect() will execute the callback function immediately. If the function produces side effects at this time, Vue will automatically track the dependencies of the side effects and automatically analyze the source of the response.
In this example, the callback is executed immediately.
During execution, it automatically tracks url.value as a dependency (similar to the behavior of computed properties). Whenever url.value changes, the callback will be executed again.
Both watch and watchEffect can reactively execute callbacks with side effects.
The main difference between them is the way reactive dependencies are tracked:
watch : Only trace data sources that are explicitly listened to. It doesn't track anything accessed in the callback. Also, the callback is only fired when the data source actually changes. watch will avoid tracking dependencies when side effects occur, so we can more precisely control when the callback function is triggered.
watchEffect: will track dependencies during side effects. It will automatically track all accessible reactive properties during synchronous execution. This is more convenient, and the code tends to be cleaner, but sometimes its responsive dependencies are less explicit.
6. Trigger timing of callback
When you change the reactive state, it may trigger both Vue component updates and listener callbacks.
By default, user-created listener callbacks are called before any Vue components are updated. This means that the DOM you access in the listener callback will be the state before it was updated by Vue.
If you want to be able to access the DOM after being updated by Vue in the listener callback, you need to specify the flush: 'post' option:
The post-refresh watchEffect() has a more convenient alias watchPostEffect():
Seven, stop the listener
A listener created with a synchronous statement in setup() or <script setup> will be automatically bound to the host component instance, and will automatically stop when the host component is unloaded.
Therefore, in most cases, you don't need to care about how to stop a listener.
One key point is that listeners must be created with synchronous statements: if you create a listener with an asynchronous callback, then it will not be bound to the current component and you must stop it manually to prevent memory leaks.
To manually stop a listener, call the function returned by watch or watchEffect:
Note that there are very few cases where listeners need to be created asynchronously, so choose synchronous creation whenever possible. If you need to wait for some asynchronous data, you can use conditional listening logic: