基本使用
在某些情况下,我们需要在状态改变的时候去执行一些其他的逻辑,如更改DOM、根据异步返回的结果去修改另一处状态。这时,我们可以用 watch
函数在每次响应式状态发生变化时,去执行相应的回调函数。
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
const question = ref('');
/**
* 第一个参数:需要监听变化的数据源,可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组
*/
watch(question, (newVal, oldValue) => {
// do something...
})
const obj = reactive({
name: '123'
})
/**
* 监听对象属性变化
* 使用getter函数
*/
watch(() => obj.name, newVal => {
// do something....
})
</script>
注意:
(1)不能直接监听响应式对象的属性,如果需要对对象属性进行监听,应该使用一个返回该属性的getter函数。
(2)如果监听的是一个响应式对象,该回调函数在所有嵌套的变更时都会被触发。
深层侦听器
当监听一个响应式对象时,会隐式的创建一个深层侦听器。同时,我们也可以通过deep属性,将侦听器强行转换为深层侦听器。
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
const obj = reactive({
name: '123'
})
/**
* 监听对象
*/
watch(() => obj.name, (newValue, oldValue) => {
// 注意:`newValue` 此处和 `oldValue` 是相等的
// *除非* state.someObject 被整个替换了!
}, {deep: true})
</script>
注意:深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。
即时回调侦听器
默认情况下,侦听器只有当数据源发生变化时,才会执行回调函数。但是,如果我们需要请求一些初始数据,然后在相关数据变化后,重新请求数据时,那么就需要在创建侦听器的时候,就立即执行回调函数。
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
const obj = reactive({
name: '123'
})
/**
* 监听对象
*/
watch(() => obj.name, (newValue, oldValue) => {
// 创建时,默认执行一遍
}, {immediate: true})
</script>
watchEffect
()
<script setup lang="ts">
import { watchEffect , reactive } from 'vue'
const obj = reactive({
name: '123'
})
/**
* 监听对象
*/
watchEffect(async () => {
// 创建时,默认执行一遍
const result = await fetch('url?name=' + obj.name)
console.log(result);
})
</script>
watchEffect()函数允许我们自动跟踪回调的响应式依赖。如上面例子,每当obj.name发生变化的时候,回调函数都会执行。
watchEffect和watch的区别:
(1)watch只会追踪明确指定的监听对象属性,只有数据源确实改变时,才会触发回调;因此,可以精确的控制回调触发的时机;
(2)watchEffect会在同步执行过程中,自动追踪所有能访问到的响应式属性。对于有多个依赖项的侦听器而言,使用watchEffect可以更加的便捷;同时,watchEffect比深层侦听器更加有效,因为其只会跟踪使用到的属性,而不是递归的跟踪所有属性。
回调的触发时机
当响应式状态更新时,会同时触发vue组件的更新和侦听器的回调。但默认情况下,会先调用侦听器,再进行vue组件的更新,这意味着侦听器内访问的DOM是Vue更新之前的状态。
如果想要再vue更新完成后,调用侦听器,可以添加flush选项:
<script setup lang="ts">
import { watchEffect, watch, reactive, watchPostEffect } from 'vue'
const obj = reactive({
name: '123'
})
/**
* 监听对象
*/
watch(() => obj.name, (newValue, oldValue) => {
//
}, { flush: 'post' })
watchEffect(async () => {
// 创建时,默认执行一遍
const result = await fetch('url?name=' + obj.name)
}, { flush: 'post' })
/**
* 同上面watchEffect 中设置 flush: 'post'
* 这个是快捷写法
*/
watchPostEffect(() => {
/* 在 Vue 更新后执行 */
})
</script>
Comments NOTHING