watch
Both and watchEffect
are vue3
listeners, but there are differences in writing and usage. This is mainly to introduce the usage of watch
and watchEffect
and the differences between them.
How watches work : Listen to a specific data source and perform side effects in a callback function. It is lazy by default - the callback is only executed when the listened source changes, however, you can configure immediate to true to specify the initial execution immediately the first time. Deep monitoring can be specified by configuring deep to true
immdiate : By default, the listener needs to change the value behind the data to take effect. If the listener needs to take effect as soon as it enters the page, you need to use immediate
deep : By default, the listener will only monitor the changes of the data itself. If you want to monitor deeply, you need to use deep. immediate and deep are configured in the third parameter object
The first parameter: who to listen to, the second parameter: the callback function, the third parameter: the configuration object
watch monitors a single data
<template>
<input type="text" v-model="text1" />
</template>
<script setup>
import { ref, watch } from 'vue'
const text1 = ref('')
watch(text1, (newVal, oldVal) => {console.log('监听单个数据', newVal, oldVal)
})
</script>
Listen to multiple data (initial value is empty, and not printed)
<template>
<input type="text" v-model="text1" placeholder="text1值" />
<hr />
<input type="text" v-model="text2" placeholder="text2值" />
</template>
<script setup>
import { ref, watch, reactive } from 'vue'
const text1 = ref('')
const text2 = ref('')
watch([text1,text2], (newValue, oldValue) => {
console.log('监听一组数据变化', newValue, oldValue)
})
// { immediate: true }
</script>
Listening to an object - the question
<template>
name: <input type="text" v-model="student.name" />
<hr/>
age: <input type="number" v-model="student.age" />
</template>
<script setup> import { reactive, watch } from 'vue'
const student = reactive({name: '',age: ''
})
watch(student, (newVal, oldVal) => {
console.log('newVal', newVal)
console.log('oldVal', newVal)
}) </script>
Listen to a certain value of the object
<template>
name: <input type="text" v-model="student.name" />
<hr />
age: <input type="number" v-model="student.age" />
</template>
<script lang="ts" setup>
import { reactive, watch } from 'vue'
const student = reactive({
name: '', age: ''
})
watch(() => student.name, (newVal, oldVal) => {
console.log('newVal', newVal)
console.log('oldVal', newVal)
}, {
deep: true, immediate: true
})
</script>
Encountered pits:
1. When monitoring the responsive data defined by reactive: oldValue cannot be obtained correctly, and deep monitoring is forced to be turned on (deep configuration is invalid)
<template>
<h2>姓名:{
{ person.name }}</h2>
<h2>年龄:{
{ person.age }}</h2>
<h2>薪资:{
{ person.job.j1.salary }}K</h2>
<button @click="person.name += '~'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
<hr />
<input type="text" v-model="text1" />
</template>
<script>
import { reactive, watch, ref } from 'vue'
export default {
setup() {
//数据
let person = reactive({
name: '张三',
age: 18,
job: {
j1: {
salary: 20
}
}
})
const text1 = ref('')
/* 情况三:监视reactive所定义的一个响应式数据的全部属性
1.注意:此处无法正确的获取oldValue
2.注意:强制开启了深度监视(deep配置无效)-不管嵌套有多深
*/
watch(person, (newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}, { deep: false }) //此处的deep配置无效 */
watch(text1, (newVal, oldVal) => {
console.log('监听单个数据', newVal, oldVal)
})
//返回一个对象(常用)
return {
person, text1
}
}
}
</script>
2. When monitoring a certain attribute in the responsive data defined by reactive: the deep configuration is valid
<template>
<h2>姓名:{
{ person.name }}</h2>
<h2>年龄:{
{ person.age }}</h2>
<h2>薪资:{
{ person.job.j1.salary }}K</h2>
<button @click="person.name += '~'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
<hr />
<input type="text" v-model="text1" />
</template>
<script>
import { reactive, watch, ref } from 'vue'
export default {
setup() {
//数据
let person = reactive({
name: '张三',
age: 18,
job: {
j1: {
salary: 20
}
}
})
const text1 = ref('')
/* 情况三:监视reactive所定义的一个响应式数据的全部属性
1.注意:此处无法正确的获取oldValue
2.注意:强制开启了深度监视(deep配置无效)-不管嵌套有多深
*/
watch(person, (newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}, { deep: false }) //此处的deep配置无效 */
watch(text1, (newVal, oldVal) => {
console.log('监听单个数据', newVal, oldVal)
})
watch(() => person.age, (newValue, oldValue) => {
console.log('person的age变化了', newValue, oldValue)
}, { deep: true }) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
//返回一个对象(常用)
return {
person, text1
}
}
}
</script>
3. When using ref to define an array: (when changeArr is triggered, it cannot be monitored)
<template>
<button @click="changeArr">按钮</button>
</template>
<script>
import { reactive, watch, ref } from 'vue'
export default {
setup() {
const array = ref([1, 2, 3]);
const changeArr = () => {
console.log('触发');
array.value = [];
}
watch(array.value, (now, old) => {
console.log(now, old); // 触发changeArr的时候,监听不到
})
return {
array, changeArr
}
}
}
</script>
solution:
<template>
<button @click="changeArr">按钮</button>
</template>
<script>
import { reactive, watch, ref } from 'vue'
export default {
setup() {
const array = ref([1, 2, 3]);
const changeArr = () => {
console.log('触发');
array.value = [];
}
// watch(array.value, (now, old) => {
// console.log(now, old); // 触发changeArr的时候,监听不到
// })
watch(() => [array.value], (now, old) => {
console.log(now, old)
})
return {
array, changeArr
}
}
}
</script>
watchEffect
Features of the watchEffect function:
-
advantage:
-
Dependencies will be collected automatically, and there is no need to manually pass the listening content - automatically listening to the responsive data used in the callback function.
-
The default immdiate is true, so it will be executed immediately during initialization.
-
-
shortcoming:
-
Unable to get the value before the change (oldVal).
-
watch()
It is executed lazily: the callback will only be executed when the data source changes. But in some scenarios, we want to execute the callback immediately when the listener is created.
watchEffect
It is equivalent to watch
merging the dependency source and the callback function. When any reactive dependencies you use are updated, the callback function will be re-executed. Unlike watch
, watchEffect
the callback function will be executed immediately (ie { immediate: true }
)
In short, watchEffect is a reactive API in Vue3 that allows you to monitor reactive state changes and trigger side effects when they change. This feature is very useful. When we need to operate on responsive data, we can react immediately after listening to changes.
<template>
name: <input type="text" v-model="student.name" />
age: <input type="number" v-model="student.age" />
</template>
<script setup>
import { reactive, watchEffect } from 'vue'
const student = reactive({name: '',age: ''
})
watchEffect(() => {console.log('name: ',student.name, 'age: ', student.age)
})
</script>
watcheffect stop listening
<template>
<div>
<input type="text" v-model="obj.name">
<button @click="stopWatchEffect">停止监听</button>
</div>
</template>
<script>
import { reactive, watchEffect } from 'vue';
export default {
setup() {
let obj = reactive({
name: 'zs'
});
const stop = watchEffect(() => {
console.log('name:', obj.name)
})
const stopWatchEffect = () => {
console.log('停止监听')
stop();
}
return {
obj,
stopWatchEffect,
}
}
}
</script>
side effects of watchEffect
What is a side effect ( side effect
), simply speaking, a side effect is to perform some kind of operation, such as modification of external variable data or variables, call of external interface, etc. watchEffect
The callback function is a side effect function, because we use watchEffect
it to perform certain operations after listening to changes in dependencies.
Vue3
The function passed in by the watchEffect
listening side effect can receive a onInvalidate
function as an input parameter, which is used to register the callback when the cleanup fails
This invalidation callback will be triggered when:
-
when the side effect is about to be re-executed (i.e. the value of the dependency changes)
-
The listener is stopped (stop listening by explicitly calling the return value, or implicitly calling stop listening when the component is unmounted)
import { watchEffect, ref } from 'vue'
const count = ref(0)
watchEffect((onInvalidate) => {
console.log(count.value)
onInvalidate(() => {
console.log('执行了onInvalidate')
})
})
setTimeout(()=> {
count.value++
}, 1000)
The order in which the above code prints is: 0
-> 执行了onInvalidate,最后执行
->1
count
Analysis: The value is printed first during initialization 0
, and then the timer count
updates the value to 1
, and the side effect is about to be re-executed at this time, so onInvalidate
the callback function will be triggered, printed 执行了onInvalidate
, and then the side effect function is executed to print count
the value 1
.
import { watchEffect, ref } from 'vue'
const count = ref(0)
const stop = watchEffect((onInvalidate) => {
console.log(count.value)
onInvalidate(() => {
console.log('执行了onInvalidate')
})
})
setTimeout(()=> {
stop()
}, 1000)
The above code: When we show that the execution stop
function stops listening, onInvalidate
the callback function will also be triggered at this time. Similarly, watchEffect
when the component is uninstalled, the function will be implicitly stop
called to stop listening, so onInvalidate
the callback function can also be triggered.
【Notice】:
watchEffect
It will be used extensively in Vue3 development. Here are a few points for attention:
-
If there are multiple negative effects, do not glue them together, it is recommended to write more than one
watchEffect
.
watchEffect(() => {
setTimeout(() => console.log(a.val + 1), 1000);
setTimeout(() => console.log(b.val + 1), 1000);
});
//错误的
These two setTimeouts are two irrelevant effects, you don’t need to monitor a and b at the same time, you can write them separately
watchEffect(() => {
setTimeout(() => console.log(a.val + 1), 1000);
});
watchEffect(() => {
setTimeout(() => console.log(b.val + 1), 1000);
});
2. watchEffect
It can also be placed in other life cycle functions
onMounted(() => {
watchEffect(() => {
// access the DOM or template refs
});
}
Summarize
watch
Lazy execution of side effects - you need to manually specify what to listen to, and also specify the callback to listen to.
The default immdiate is false, so it will not be executed during initialization, and the callback will only be executed when the listened source data changes.
No return value is required.
You can get the value before the change (oldVal)
watchEffect
Automatically collect dependencies, no need to manually pass listening content - automatically listen to the responsive data used in the callback function
The default immdiate is true, so it will be executed immediately during initialization, and the callback will also be executed when the source data changes.
No return value is required.
Unable to get the value before the change (oldVal)