watch()
是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,希望在创建,就立即执行一次(我们也可以使用watch()
,设置{immediate: true}
),此时我们可以使用watchEffect
侦听器
const url = ref('https://...')
const data = ref(null)
async function fetchData() {
const response = await fetch(url.value)
data.value = await response.json()
}
// 立即获取
fetchData()
// ...再侦听 url 变化
watch(url, fetchData)
我们可以用watchEffect
函数来简化上面的代码。watchEffect
会立即执行一遍回调函数,如果这时函数产生了副作用,Vue会自动追踪副作用的依赖关系,自动分析出响应源。上面的例子可以重写为
watchEffect(async () => {
const response = await fetch(url.value)
data.value = await response.json()
})
在这个例子中,回调函数会立即执行。在执行期间,它会自动追踪url.value
作为依赖。每当url.value
变化时,回调函数会再次执行
注意:watchEffect
仅会在其同步执行期间,才会被追踪。在使用异步回调时,只有第一个await
正常工作前访问到的属性才会被追踪
watch
和watchEffect
都能响应式地执行有副作用的回调。它们之前的主要区别是追踪响应式依赖的方式:
watch
只追踪明确侦听的数据源。它不会追踪任何在回调函数中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch
会避免在发生副作用时追踪依赖,因此,我们能更加精准的控制回调函数的触发时机watchEffect
,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动的追踪所有能访问到的响应式数据。这更方便,而且代码往往更简洁,但有时其依赖关系会不那么明确在setup()
或中用同步语句创建的侦听器,会自动绑定到宿主组件实例上,并且会在宿主组件写在时自动停止
侦听器必须使用同步语句创建,如果使用异步语回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏
要手动停止一个侦听器,请调用watch
或watchEffect
返回的函数
const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时
unwatch()
注意,需要异步创建侦听器的情况很少,请尽可能选择同步创建。如果需要等待一些异步数据,你可以使用条件式的侦听逻辑:
使用异步创建侦听器,可以将异步操作提到侦听器外,将异步操作的结果放到侦听器内
// 需要异步请求得到的数据
const data = ref(null)
watchEffect(() => {
if (data.value) {
// 数据加载后执行某些操作...
}
})