vite+vue3+ts中watch和watchEffct的使用
本文目录
- vite+vue3+ts中watch和watchEffct的使用
- watch
- ref
- reactive
- props
- immediate
- 组合监听
- watchEffect
- 单值多值侦听
- 副作用
- 停止监听
watch
vue官方文档:https://cn.vuejs.org/api/reactivity-core.html#watch
可以监听基础类型,整个对象,对象的某个属性
ref
对于基本数据类型(如字符串、数字),ref 提供了完整的响应式特性
对于对象,ref 也可以使其成为响应式,但 watch 默认不进行深度监听,需要手动指定 deep 选项
ref基础类型:直接监听,可获取新旧值
const num = ref(1);
const changeValue = function () {
num.value++;
};
watch(num, (newValue, oldValue) => {
console.log("监听变化", newValue, oldValue);
});
- ref对象类型:需要显式开启深度监听,但是只能获取新值
需要使用深度监听,由于 JavaScript
对象和数组的引用特性,newValue
和 oldValue
会指向相同的内存地址;因此,在数据变化后,newValue
和 oldValue
是相同的
const count = ref({
a: 1,
b: 2,
});
const changeValue = function () {
count.value.a ++;
};
// 不生效
watch(count, (newValue, oldValue) => {
console.log("监听变化", newValue, oldValue);
});
// 生效,添加deep
watch(count, (newValue, oldValue) => {
console.log('监听变化deep', newValue, oldValue)
}, { deep: true })
把watch的引用类型数据源浅拷贝了一份,即可完成对新旧值得获取(多层数据需要使用深拷贝)
watch(
() => {
return { ...count.value };
},
(newValue, oldValue) => {
console.log("监听变化deep-return\n", newValue, oldValue);
},
{ deep: true }
);
- ref对象的单个属性
此时第一个参数是一个箭头函数
watch(() => count.value.a, (newValue, oldValue) => {
console.log("监听变化ref单个\n", newValue, oldValue);
});
- ref数组类型
const list = ref([1, 2, 3, 4, 6]);
const changeValue = function () {
list.value[0] ++;
};
watch(
list,
(newValue, oldValue) => {
console.log("监听变化list-deep\n", newValue, oldValue);
},
{ deep: true }
);
- ref对象数组类型
const list = ref([
{ a: 1, b: 1 },
{ a: 1, b: 1 },
]);
const changeValue = function () {
list.value[0].a++;
};
watch(
list,
(newValue, oldValue) => {
console.log("监听变化list-deep\n", newValue, oldValue);
},
{ deep: true }
);
使用深拷贝获取旧值
watch(
() => JSON.parse(JSON.stringify(list.value)),
(newValue, oldValue) => {
console.log("监听变化deep-return\n", newValue, oldValue);
},
{ deep: true }
);
reactive
reactive 用于创建一个深层次的响应式对象
对于 reactive 对象,watch 默认执行深度监听
- reactive对象整体:直接监听,只能获取到新值
const demo = reactive({
name: "aaa",
item: {
name: "",
num: 1,
},
});
const changeValue = function () {
demo.item.num++;
};
watch(demo, (newValue, oldValue) => {
console.log("监听变化reactive\n", newValue, oldValue);
});
- reactive对象单个属性
watch(() => demo.item.num, (newValue, oldValue) => {
console.log("监听变化reactive单个\n", newValue, oldValue);
});
props
使用 getter
函数返回值的形式,默认不开启深度监听
- 父组件
<WatchB :item="demo"></WatchB>
const demo = reactive({
name: "aaa",
num: 1,
item: {
name: "",
num: 1,
},
});
- 子组件
const props = defineProps(["item"]);
const ite = ref();
ite.value = props.item;
watch(
() => props.item,
(newVal, oldVal) => {
console.log(ite.value);
},
{ deep: true }
);
immediate
默认情况下watch
是懒加载的,设置immediate: true
时,会在初始化时立即执行回调函数
{ deep: true, immediate: true }
组合监听
在组合监听的情况下,Vue
需要明确知道是否需要对 reactive
对象进行深度监听,所以需要显式开启深度监听
第一个参数是一个数组
watch(
[() => demo, num],
([newDemo, newNum], [oldDemo, oldNum]) => {
console.log("watch 已触发: demo", newDemo, oldDemo);
console.log("watch 已触发: num", newNum, oldNum);
},
{ deep: true }
);
watchEffect
在 watchEffect 的回调中,任何访问的响应式引用都会被追踪,当这些引用的值发生变化时,watchEffect 的回调会自动重新执行
watchEffect 适用于需要自动追踪多个数据源的场景,如副作用操作,用于清理或重置副作用(如定时器、订阅等)
watchEffect默认初始时就会执行第一次,一旦运行就会立即监听,组件卸载的时候会停止监听
watchEffect 无法获取到变化前的值,只能获取变化后的值
vue官方文档:https://cn.vuejs.org/api/reactivity-core.html#watcheffect
单值多值侦听
const number = reactive({ count: 0 });
const countAdd = () => {
number.count++;
};
watchEffect(()=>{
console.log("新的值:", number);
})
watchEffect
本身不会进行深度监听,它只会自动跟踪其回调函数中所引用的响应式状态(通过 ref
或 reactive 创建的状态)的变化。如果在 watchEffect
中引用了一个 reactive
对象的某个属性,它只会在那个具体属性发生变化时触发
const demo = reactive({
name: "aaa",
num: 1,
item: {
name: "",
num: 1,
},
});
watchEffect(() => {
console.log("demo-num的变化后的值\n", demo.item.num);
});
watchEffect
只会在 demo.item.num
发生变化时触发。对于 demo
或 demo.num
的变化,watchEffect
不会响应,因为它没有被 watchEffect
的回调函数所引用
watchEffect(() => {
console.log("demo的变化后的值\n", demo);
});
副作用
// 副作用
const v3 = ref(3)
watchEffect(()=>{
const v = v3.value
// 存在异步
setTimeout(()=>{
console.log(v,'timeout')
},1000);
})
watchEffect(async onInvalidate=>{
const v = v3.value
// 存在异步
const timeout = setTimeout(()=>{
console.log(v,'timeout')
},1000);
onInvalidate(()=>{
clearTimeout(timeout)
})
})
重复执行会触发 onInvalidate
,取消上一次的异步请求
停止监听
const stop = watchEffect(() => {
console.log("name:", demo.item.num);
});
const stopWatchEffect = () => {
console.log("停止监听");
stop();
};