preamble
The watch API should be familiar to everyone, and in the Vue3 version of the watch to add a lot of useful functions, such asThe dep option supports passing in numbers
、pause, resume, stop methods
、once option
、onCleanup function
These features are not usually used by everyone, but they can play a big role in some specific scenarios. These features are not usually used by everyone, but in some specific scenarios, they can play a big role, this article Ouyang will take you to inventory these features.
Follow the public number: [Front-end Ouyang], give yourself a chance to advance vue
deep
Support for incoming numbers
deep
The options should be familiar to you, and the common values aretrue
orfalse
If you want to listen in depth, you can do so by clicking the "Listen in depth" button.watch
The incoming object.
In the Vue 3.5 release there is a change to thedeep
option has been enhanced to support not only boolean values, but also passing in numbers, which indicate the number of layers to listen on.
Take for example the following example:
const obj1 = ref({
a: {
b: 1,
c: {
d: 2,
e: {
f: 3,
},
},
},
});
watch(
obj1,
() => {
("I'm listening in.obj1variations");
},
{
deep: 3,
}
);
function changeDeep3Obj() {
= 20; // able to triggerwatchpull back (of a key (in music)
}
function changeDeep4Obj() {
= 30; // cannot be triggeredwatchpull back (of a key (in music)
}
In the example abovewatch
(used form a nominal expression)deep
An option value of 3 indicates listening to layer 3 of the object.
changeDeep3Obj
function is to modify the object's 3rd level of thed
attribute, so it can trigger thewatch
The pullback.
(indicates contrast)changeDeep4Obj
function is to modify the object's level 4f
attribute, so it can't trigger thewatch
The pullback.
His implementation is also very simple, let's look at the DEEP related source code:
function watch(source, cb, options) {
// ...an omission
if (cb && deep) {
const depth = deep === true ? Infinity : deep
getter = () => traverse(baseGetter(), depth)
}
// ...an omission
}
Here.depth
It means that watch listens to the depth of an object.
in the event thatdeep
option has a value of true, then thedepth
Set to positive infinityInfinity
, indicating the need to listen to the deepest part of the object.
in the event thatdeep
option has a value of false or is not passed into thedeep
, then it indicates that only the outermost level of the object needs to be listened to.
in the event thatdeep
option has a value of type number, then assign the number to thedepth
, indicating the need to listen to a specific layer of the object.
pause, resume, stop methods
These three methods were also introduced in Vue 3.5, by deconstructing thewatch
The return value of the function can then be gotten directlypause
、resume
、stop
These three methods.
Let's look at the source code, which is actually quite simple:
function watch(source, cb, options) {
// ...an omission
= (effect)
= (effect)
= watchHandle
return watchHandle
}
Overwatch returns a file namedwatchHandle
object, which has on top of it thepause、resume、stop
These three methods so that we can deconstruct thewatch
The return value of the function gets these three methods.
pause
method serves to "pause" the trigger of the watch callback, i.e., its callback function will not be triggered during the pause, regardless of any changes to the responsive variables that the watch listens to.
If there is a "pause", then there must be a "resume".
resume
The role of the method is to resume the triggering of the watch callback, at which point it will actively execute the watch callback once. Later, when the responsive variable that watch listens to changes, his callback function will also trigger.
Let's take a look at the demo, the code is as follows:
<template>
<button @click="count++">count++</button>
<button @click="()">pause (media player)</button>
<button @click="()">resumption</button>
<button @click="()">cessation</button>
</template>
<script setup lang="ts">
import { watch, ref } from "vue";
const count = ref(0);
const runner = watch(count, () => {
();
});
</script>
Clicking on the "count++" button will cause thewatch
console execution in the callback.
But when we click on the "pause" button, no matter how much we click on the "count++" button, it won't trigger thewatch
The pullback.
strike (on the keyboard)resumption
button will be triggered once immediately after thewatch
The callback is executed, and clicking on the "count++" button later will also trigger thewatch
The pullback.
Let's see.pause
cap (a poem)resume
The source code for the method, which is very simple, is as follows:
class ReactiveEffect {
pause(): void {
|=
}
resume(): void {
if ( & ) {
&= ~
if ((this)) {
(this)
()
}
}
}
trigger(): void {
if ( & ) {
(this)
} else if () {
()
} else {
()
}
}
}
existpause
、resume
method by modifying theflags
property to toggle whether it is "paused" or not.
in implementingtrigger
When the method dependency is triggered, it goes ahead and reads theflags
attribute determines if the current state is "paused", and if so, the watch callback is not executed.
As you can see from the code above these three methods are in theReactiveEffect
class above, thisReactiveEffect
class is an underlying class of Vue.watch
、watchEffect
、watchPosEffect
、watchSyncEffect
are all implemented based on this class, so naturally they support thepause
、resume
、stop
These three methods.
endstop
method, and when you're sure you don't want to trigger the watch callbacks anymore, call thestop
method. The code is as follows:
const watchHandle: WatchHandle = () => {
()
if (scope && ) {
remove(, effect)
}
}
= watchHandle
responsive variablecount
The collected set of subscribers has this watch callback, so when thecount
will trigger the watch callback when its value changes. Here thestop
method relies heavily on a two-way linked list to pull this watch callback from the responsive variablecount
is removed from the subscriber collection, so after executing the stop method whatever thecount
How the value of the variable changes, the watch callback will not be executed anymore. (PS: If you can't understand this paragraph, I suggest you go check out my last postVue3.5 Bidirectional Chained Tables(Article, read it and you'll understand)
once option
If you only want your watch callbacks to execute once, then try thisonce
option, which is new in Vue 3.4.
Look at a demo:
<template>
<button @click="count++">count++</button>
</template>
<script setup lang="ts">
import { watch, ref } from "vue";
const count = ref(0);
watch(
count,
() => {
("once", );
},
{
once: true,
}
);
</script>
As a result of the use ofonce
option, so only the first click on the "count++" button will trigger the watch callback. Any subsequent clicks on the button will not trigger the watch callback.
Let's see.once
The source code for the option, which is very simple, is as follows:
function watch(source, cb, options) {
const watchHandle: WatchHandle = () => {
()
if (scope && ) {
remove(, effect)
}
}
if (once && cb) {
const _cb = cb
cb = (...args) => {
_cb(...args)
watchHandle()
}
}
// ...an omission
= (effect)
= (effect)
= watchHandle
return watchHandle
}
Let's look at the code in the middle firstif (once && cb)
The phrase means that ifonce
option has a value of true and the watch callback is also passed in. Then encapsulate a new layer ofcb
callback function, which still executes the watch callback passed in by the user in a new callback function. It then goes on to execute awatchHandle
function, thiswatchHandle
Doesn't that look familiar?
aforementionedstop
method is actually executing thiswatchHandle
After executing thiswatchHandle
function, watch no longer listens to thecount
variable is up, so it doesn't matter if the subsequentcount
How the variable is modified, the watch callback will not be triggered again.
onCleanup function
There are situations where we need watch to listen on a variable and then go to initiate a http request. If the variable changes quickly, the second request will be initiated before the first request comes back. In some extreme cases, the response to the first request will be slower than the response to the second request, and the return value from the first request will overwrite the return value from the second request. In fact, we expect to get the return value of the second request in the end.
In this case we can use theonCleanup function
, who is exposed to us as the third parameter of the watch callback. Look at an example:
watch(id, async (newId, oldId, onCleanup) => {
const { response, cancel } = myFetch(newId)
// When `id` changes, `cancel` will be called.
// cancel the previous outstanding request
onCleanup(cancel)
= await response
})
The first two parameters of the watch callback are familiar: the new id value and the old id value. The third parameter is theonCleanup
function, which is called before the watch callback is triggered, so we can use him to cancel the last request.
onCleanup
The registration of the function is also simple with the following code:
let boundCleanup
boundCleanup = fn => onWatcherCleanup(fn, false, effect)
function watch(source, cb, options) {
// ...an omission
const job = (immediateFirstRun?: boolean) => {
const args = [
newValue,
oldValue,
boundCleanup,
]
cb(...args)
oldValue = newValue
}
// ...an omission
}
Executing the watch callback is actually executing thisjob
function in thejob
Three parameters are passed in to the function to execute the watch callback. These arenewValue
、oldValue
、boundCleanup
. The first two parameters are familiar to everyone, and the third parameterboundCleanup
is a function:fn => onWatcherCleanup(fn, false, effect)
。
this oneonWatcherCleanup
Are you all familiar with this? This is also an API exposed by Vue, registering a cleanup function to be executed when the current listener is about to be re-run. There's a lot of information about theonWatcherCleanup
Previously Ouyang wrote an article dedicated to how to use it:Wrapping the auto-cancel fetch function with Vue 3.5's onWatcherCleanup
summarize
This post takes stock of some of the new features added to Vue3 watch:The dep option supports passing in numbers
、pause, resume, stop methods
、once option
、onCleanup function
The following are some of the features that you may not normally use. These are features that you may not normally use, but it is still important to know that they are there because there are situations where they can come in handy.
Follow the public number: [Front-end Ouyang], give yourself a chance to advance vue
Also Ouyang wrote an open source ebookvue3 Compilation Principles Revealed, reading this book can give you a qualitative improvement in your knowledge of vue compilation. This book is accessible to beginner and intermediate front-ends and is completely free, just asking for a STAR.