I. Use of Watch
watch(WatcherSource, Callback, [WatchOptions])
type WatcherSource<T> = Ref<T> | (() = > T)
interface WatchOptions extendsWatchEffectOptions { -- deep? : boolean` `// Default: false '-- immediate? : boolean` `// Default: false '
}
Copy the code
Parameter Description:
- WatcherSource: Used to specify the reactive variable to listen for. A WatcherSource can pass in ref-responsive data, and reactive objects are written as functions.
- Callback: Callback function to execute, receiving the current value newValue and the previous value oldValue as input arguments.
- WatchOptions: Supports deep and immediate. Set deep: true when deep listening on responsive objects is required. Watch is lazy by default, and when we set immediate: true, watch will execute the callback function immediately upon initialization.
- In addition, VuE3’s Watch also supports listening on multiple responsive data, and can also manually stop watch listening.
1, the introduction ofwatch
import { watch } from 'vue'
Copy the code
Then inject listener events into setup
setup(props){
const state = reactive({
count: 0 ,
message:'Hellow world'
});
watch(state,() = >{
console.log(state.count); -- single listener})return {
state,
}
},
Copy the code
2. Multiple data sources monitoring
<template> <div> age: {{obj1.age}}<br> name: {{obj.name}} <br> list: <ul> <li v-for="(item, Index in obj.list" :key="index"> {{item}} </li> </ul> <hr> <button @click="changeName"> changeName </button> <button @click="changeList"> changeList </button> <button @click="changeAge"> changeAge </button> </div> </template> <script lang="ts"> import {defineComponent, reactive, watch} from 'vue'; export default defineComponent({ setup () { let obj = reactive({ name: '1111', list: ['222', '222222', '222222'] }) let obj1 = reactive({ age: 18 }) function changeName () { obj.name += '+' } function changeList () { obj.list[0] += '+' } function changeAge () { Obj1.age ++} watch([obj, obj1], () => {console.log(obj.name) if(obj.age>28){watchFunc() // Stop listening '}}, {// The page is loaded immediately: true }) return { obj, changeName, changeList, changeAge, obj1 } } }) </script> <style scoped> </style>Copy the code
The result: The Watch picks up on changes in data when names and ages are changed. When age is greater than 28, we stop listening, and then change the age. Because of the stop of Watch, the callback function of Watch becomes invalid.
Workaround: We can listen for multiple value changes with watch, or we can stop listening by giving the watch function a name and executing the name () function.
3. Listen for array changes
<template>
<div class="watch-test">
<div>{{arrayRef}}</div>
<div>{{arrayReactive}}</div>
</div>
<div>
<button @click="changeArrayRef">Change ref to define the first item in the array</button>
<button @click="changeArrayReactive">Change the first item in the reactive definition array</button>
</div>
</template>
<script>
import {ref, reactive, watch} from 'vue'
export default {
name: 'WatchTest'.setup() {
const arrayRef = ref([1.2.3.4])
const arrayReactive = reactive([1.2.3.4])
//ref not deep
const arrayRefWatch = watch(arrayRef, (newValue, oldValue) = > {
console.log('newArrayRefWatch', newValue, 'oldArrayRefWatch', oldValue)
})
//ref deep
const arrayRefDeepWatch = watch(arrayRef, (newValue, oldValue) = > {
console.log('newArrayRefDeepWatch', newValue, 'oldArrayRefDeepWatch', oldValue)
}, {deep: true})
//reactive, sources are not functions
const arrayReactiveWatch = watch(arrayReactive, (newValue, oldValue) = > {
console.log('newArrayReactiveWatch', newValue, 'oldArrayReactiveWatch', oldValue)
})
// Best practice of array listening - reactive and source function return, return copied data
const arrayReactiveFuncWatch = watch(() = > [...arrayReactive], (newValue, oldValue) = > {
console.log('newArrayReactiveFuncWatch', newValue, 'oldArrayReactiveFuncWatch', oldValue)
})
const changeArrayRef = () = > {
arrayRef.value[0] = 6
}
const changeArrayReactive = () = > {
arrayReactive[0] = 6
}
return {
arrayRef,
arrayReactive,
changeArrayRef,
changeArrayReactive
}
}
}
</script>
Copy the code
If deep:true is not added, watch cannot listen for the change of value. With deep:true, watch can detect changes in the data, but the old value is the same as the new value, that is, it cannot fetch the old value. When the array is defined as a responsive object, watch can detect the change of data without any processing, but the old value is the same as the new value. If the data source of Watch is written as a function and a set of numbers is returned by cloning the extended operator, the new and old values can be obtained at the same time while listening.
Conclusion: When defining an array, it is better to define the data as a reactive object. In this way, when watch listens, it only needs to write the data source as a function and clone a set of returns by extending the operator, so that it can obtain new and old values while listening.
4. Listening object
<template>
<div class="watch-test">
<div>user:{</div>
<div>name:{{objReactive.user.name}}</div>
<div>age:{{objReactive.user.age}}</div>
<div>}</div>
<div>brand:{{objReactive.brand}}</div>
<div>
<button @click="changeAge">Change the age</button>
</div>
</div>
</template>
<script>
import {ref, reactive, watch} from 'vue'
import _ from 'lodash';
export default {
name: 'WatchTest'.setup() {
const objReactive = reactive({user: {name: 'Komatsu Nagai'.age: '20'}, brand: 'Channel'})
//reactive sources are functions
const objReactiveWatch = watch(() = > objReactive, (newValue, oldValue) = > {
console.log('objReactiveWatch')
console.log('new:'.JSON.stringify(newValue))
console.log('old:'.JSON.stringify(oldValue))
})
//reactive, source function, deep: true
const objReactiveDeepWatch = watch(() = > objReactive, (newValue, oldValue) = > {
console.log('objReactiveDeepWatch')
console.log('new:'.JSON.stringify(newValue))
console.log('old:'.JSON.stringify(oldValue))
}, {deep: true})
// Best practice of deep object listening reactive and source function return, return deep-copy data
const objReactiveCloneDeepWatch = watch(() = > _.cloneDeep(objReactive), (newValue, oldValue) = > {
console.log('objReactiveCloneDeepWatch')
console.log('new:'.JSON.stringify(newValue))
console.log('old:'.JSON.stringify(oldValue))
})
const changeAge = () = > {
objReactive.user.age = 26
}
return {
objReactive,
changeAge
}
}
}
</script>
Copy the code
Reactive (deep:true) watch cannot listen to changes in the value of a reactive object. With deep:true, watch can detect data changes, but the old value is the same as the new value, that is, it cannot obtain the old value. If you write the watch data source as a function and return an object with a deep-copy clone (here using a deep copy of the LoDash library), you can get both the new and old values while listening.
Conclusion: When defining objects, it is better to define data as reactive objects. In this way, when watch is listening, it only needs to write data source in the form of function and return a cloned object through deep copy, so that it can obtain new and old values while listening.
5, conclusion
- 1. Generally, raw type data (number, string, etc.) is defined as ref response data, and reference type data (array, object) is defined as reactive response data;
- 2. When we use Watch to monitor data changes and need to obtain new and old values at the same time, we need to define the data source as a function and return the data source with a deep copy. When we only need the new value, we can add the deep:true option. \
- In fact, the data of reference types defined as ref form it doesn’t matter, only need to define the data source for the function form, and return the data source for deep copy, to get a new and old value ~ ha ha ha ha ha ha ha ha ha ha ha ha ha ha, but I think best practice is to define the reference type as reactive response data.