Vue 监听器
虽然计算属性在大多数情况下更合适,但有时我们需要在状态变化时执行“副作用”(side effects):例如更改 DOM,或者根据异步操作的结果去修改另一处的状态。在 Vue 中,我们可以使用监听器 (Watchers) 来响应数据的变化。
watch
watch 函数用于在某个响应式数据源发生变化时,执行一个回调函数。
基础用法
watch 接收三个参数:
- 一个想要监听的数据源 (可以是一个 ref,或一个返回值的 getter 函数)。
- 一个在数据源变化时执行的回调函数。回调函数接收新值和旧值作为参数。
- 一个可选的配置对象。
vue
<script setup>
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
// 可以直接监听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.indexOf('?') > -1) {
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
answer.value = (await res.json()).answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
}
}
})
</script>
<template>
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</template>watch vs. computed
watch 和 computed 都允许我们响应式地执行操作。主要的区别是它们的使用场景:
computed:用于派生新的数据。它是声明式的,返回一个值,并且有缓存。当你需要根据其他数据计算出一个新值时,使用计算属性。watch:用于执行副作用。它是命令式的,不返回值。当你需要在数据变化时执行异步操作、操作 DOM 或与其他系统交互时,使用监听器。
深层监听
直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发。然而,这只在整个对象被替换时才会触发。
js
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// 在 obj.count 改变时触发
})如果你想在对象内部属性变化时触发,需要使用 deep: true 选项。
js
watch(
() => state.someObject,
(newValue, oldValue) => {
// ...
},
{ deep: true }
)watchEffect
watchEffect 是 watch 的一个变体。它会立即执行一次回调函数,然后自动追踪其所有响应式依赖。当任何一个依赖发生变化时,它会重新运行该函数。
vue
<script setup>
import { ref, watchEffect } from 'vue'
const todoId = ref(1)
const data = ref(null)
watchEffect(async () => {
// 这个 effect 会立即运行,
// 然后在 todoId.value 改变时重新运行。
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
</script>
<template>
<p>Todo id: {{ todoId }}</p>
<button @click="todoId++">Fetch next todo</button>
<p v-if="!data">Loading...</p>
<pre v-else>{{ data }}</pre>
</template>watch vs. watchEffect
- 依赖追踪:
watch只追踪明确指定的数据源,而watchEffect会自动追踪其回调函数中访问的所有响应式数据。 - 惰性执行:
watch默认是惰性的(只有在数据源变化时才执行),而watchEffect会在创建时立即执行一次。 - 数据访问:
watch可以访问变化前后的值,而watchEffect不能。
选择哪个取决于你的需求。如果你需要精确控制要监听的数据,或者需要访问旧值,请使用 watch。如果你的副作用逻辑依赖于多个响应式源,并且你不需要旧值,watchEffect 会更简洁。