VUE3的watchEffect使用
VUE2.0大家都是是用過watch,可以監聽某個值的變更,可以做一些相應的事件處理。VUE3.0出來一個watchEffect的東西,我們一起看下這個api有什么用途。
與watch有什么區別?
我們先來看一個簡單watch的例子
<script lang="ts">
import {
defineComponent, watch, ref,
} from 'vue';
export default defineComponent({
setup() {
const count = ref(0);
watch(count, (val, oldVal) => {
console.log(val, oldVal);
});
setTimeout(() => {
count.value += 1; // 當值改變時執行
}, 1000);
}
});
</script>
再來看一個watchEffect的簡單例子
<script lang="ts">
import {
defineComponent, watchEffect, ref,
} from 'vue';
export default defineComponent({
setup() {
const count = ref(0);
watchEffect(() => {
console.log(count.value); // 初始化時會執行一次
});
setTimeout(() => {
count.value += 1; // 值變化時又執行了一次
}, 1000);
}
});
</script>
通過兩個簡單的例子,我們可以看得出,watch和watchEffect還是有一些區別的
watchEffect
會自動的收集依賴,而watch是明確的指定監聽某個變量watch
可以獲取到新值和舊值,watchEffect
則只能取到最新的watchEffect
會在初始化的時候執行一次,類似computed
與compute有什么區別?
同樣,我們先來看一個例子
<template>
{{sayHello}}
</template>
<script lang="ts">
import {
defineComponent, watchEffect, ref, computed,
} from 'vue';
export default defineComponent({
setup() {
const count = ref(0);
watchEffect(() => {
console.log(count.value);
});
setTimeout(() => {
count.value = 20;
}, 1000);
const name = ref('thomaskwun');
const sayHello = computed(() => {
console.log('computed', count.value);
return `我是${name.value},${count.value}歲`;
});
return {
sayHello,
};
},
});
</script>
computed和watchEffect相同的地方是會自動收集依賴,在值更新時會觸發回調,會初始化調用一次。
但是在觸發初始化的時機是不一樣的,如果computed的值沒有被使用,是不會觸發回調的,只有在該值被使用的時候才會觸發回調,但watchEffect是在setup的時候就會初始化。
根據他們的差異,我們可以在不同的業務場景下選擇合適的處理方法。
watchEffect的使用
注意事項
如果watchEffect
涉及到dom或者ref的操作,需要在onMounted
生命周期里調用
停止監聽
<script lang="ts">
import {
defineComponent, watchEffect, ref,
} from 'vue';
export default defineComponent({
setup() {
const count = ref(0);
const myWatch = watchEffect(() => {
console.log(count.value);
});
setTimeout(() => {
console.log('change');
count.value = 20;
}, 1000);
myWatch();
},
});
</script>
如果是在setup
的生命周期里聲明的watchEffect
,在組件銷毀的時候是會默認清除監聽,也可以再次調用watchEffect
顯式停止監聽。
清除副作用
const count = ref(0);
const stop = watchEffect(onInvalidate => {
const token = asyncOperate(count.value);
onInvalidate(() => { // 消除上次的副作用
token.cancel();
})
}
watchEffect進階
const count = ref(0);
const stop = watchEffect(onInvalidate => {
const token = asyncOperate(count.value);
onInvalidate(() => { // 消除上次的副作用
token.cancel();
})
}, {
flush: "sync", // 副作用的調度機制 sync, pre, post
onTrack: e => { // 調試用: 追蹤的信息
console.log(e);
},
onTrigger: e => { // 調試用:響應式信息
console.log(e);
},
})
// 如副作用中設計到DOM的操作和ref的獲取,需要放到mounted周期中執行
onMounted(() => {
watchEffect(() => { // .. 操作dom或ref等 })
})
參考資料
https://www.yuque.com/atomjaylee/fe/sm5bst
https://segmentfault.com/a/1190000023669309