目录
使用 onInvalidate() 清除 watchEffect 副作用
使用 watchEffect 返回的 stop 方法,停止 watchEffect 监听
如何使用 watch ?
Vue Options API 提供了一个 watch 选项
export default {
data () {
return {
title: 'Vue2'
}
},
watch: {
// Watcher
}
}
watch: {
title: {
handler: (newTitle, oldTitle) => {
console.log("Title changed from " + oldTitle + " to " + newTitle);
},
immediate: true,
},
},
适用场景:
- 需要控制哪些依赖项会触发该方法
- 需要访问之前的值
如何在首次监听后,自动取消 watch 监听?
调用 watch 自身,可以实现此需求
/**
* 监听 vuex 里开发者配置改变
*/
const watchInitData = watch(
() => store.state[VuexModule.ApplicationLibDevelopment],
async (newVal) => {
// 页面初始化
initPage();
// 调用 watch 本身,可以实现取消监听
watchInitData();
},
{ deep: true },
);
如果需要跟踪多个响应式变量,有什么好的解决方案吗?
在 Vue Options API(Vue2)中,可以创建多个 watch 观察者
在 Composition API(Vue3)中,可以创建多个 watchEffect 观察者;也可以只创建一个 watchEffect,但在他的回调函数中,写上所有要监听的值
watchEffect VS watch
是否需要指手动传入依赖
watch —— 既要指明监视的属性,也要指明监视的回调【需要手动传入依赖】
watchEffect —— 不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性【不需要手动传入依赖,会从回调函数中自动获取】
是否为惰性的
watch 是惰性的 —— 仅当依赖项更改时,才会触发;可以为 watch 传递一个 immediate 属性,使其在初始化时运行
watchEffect 是非惰性的 —— 在创建组件后立即运行,同时,在方法的任何依赖项发生更改时运行
每次监听依赖项时 返回的值
wach —— 每次监听,都会返回新旧值
watchEffect —— 每次监听,只会返回最新的值;只有在页面初始化时,才能拿到一次旧值
watchEffect VS computed
watchEffect 和 watch 一样,都有点像 computed
- computed 注重的计算出来的值(回调函数的返回值),所以必须要写返回值
- watchEffect 注重的是过程(回调函数的函数体),所以不用写返回值
如何使用 watchEffect ?
- 在初始化组件时立即运行(组件初始化时,watchEffect 将运行并记录起始值)
- 在依赖项发生变化时运行(当 监听对象的值 改变时,就会触发 watchEffect)
由第二点可得:在挂载 DOM 之前,尽量不要尝试访问 DOM,防止产生不必要的监听
import { ref, watchEffect } from 'vue'
export default {
setup () {
const userID = ref(233)
watchEffect(() => console.log('userID: ' + userID.value))
setTimeout(() => {
userID.value = 666
}, 500)
return {
userID
}
}
}
// 打印结果
userID: 233
userID: 666
也可以在组件中,使用 watchEffect 结合 props 进行使用
export default {
props: {
movieID: String,
},
setup(props) {
watchEffect(() => console.log(props.movieID))
},
}
使用 onInvalidate() 清除 watchEffect 副作用
每当 watchEffect 监听到了依赖项变化时,就执行一个异步请求;
但是在异步请求完成之前,依赖项又发生了变化……
如何避免再一次发请求?
export default {
setup() {
watchEffect(onInvalidate => {
// 异步请求
const apiCall = someAsyncMethod(props.songID)
onInvalidate(() => {
// 取消异步请求
apiCall.cancel()
})
})
}
}
使用 watchEffect 返回的 stop 方法,停止 watchEffect 监听
可以手动停止 watchEffect 监听
试想一下,如果你想观察一个依赖项,直到他变成某个值,就不希望继续监听了
继续监听属于浪费资源了,如何实现手动停止 watchEffect 监听?
watchEffect 返回了 stop 方法,调用它,可以手动停止 watchEffect 监听
export default {
setup (props) {
let stopWatcher = watchEffect(() => console.log(props.movieID))
stopWatcher()
}
}
使用 flush 修改 watchEffect 监听的时机
watchEffect 默认在组件加载好之前,就会调用一次监听,举个栗子:
const state = reactive({
test: {
myName: '',
}
});
state.test.myName = 'Lyrelion'
watchEffect(() => {
console.log('名字被修改了', state.test.myName );
})
/**
* 打印结果(在组件更新前,watchEffect 就执行了一次监听,所以会打印两次)
* 名字被修改了
* 名字被修改了 Lyrelion
*/
如果在组件加载好之前,我不想执行监听呢?也就是说,修改 watchEffect 监听时机
可以通过修改 watchEffect 中的 flush 属性,指定监听时机
flush 有以下三种可设置项:
- pre (默认)
- post (在组件渲染完成后触发,访问加载后的 DOM,这就可以防止初始值还没附上,就开始监听了的问题)
- sync (与 watch 一样,每个更改都强制触发侦听器,这是低效的,应该很少需要)
综上所述,为了在组件加载好之前,不执行监听,可以这么写
const state = reactive({
test: {
myName: '',
}
});
state.test.myName = 'Lyrelion'
watchEffect(() => {
console.log('名字被修改了', state.test.myName );
}, {
flush: 'post'
})
/**
* 打印结果(在组件更新前,watchEffect 就执行了一次监听,所以会打印两次)
* 名字被修改了 Lyrelion
*/
补充一篇写的不错的文章