vue3中的watch和computed钩子函数的使用下午朋友突然甩了几道面试题给我,我一看不禁笑出声来。题目是这样的:
背景
下午朋友突然甩了几道面试题给我,我一看不禁笑出声来。题目是这样的:“请解释Vue.js中的Computed与Watch,并给出示例。”我心想,这面试官也太会玩了,这不是明摆着考验面试者对Vue.js的掌握程度嘛。
(当然,我肯定不会说自己忘了,于是开始连夜恶补一番。)
Computed
// 前置数据
const fristName = ref('ha');
const lastName = ref('kwan');
1. 创建一个只读的computed Ref
创建只读的Ref可以使用回调函数(getter函数)的形式
<template>
{{ multName }}
<button @click="multName = 'aaabbb'">change multName</button>
</template>
<script setup lang="ts">
const multName = computed(() => fristName.value + ':' + lastName.value);
</script>
当点击按钮时,会发现视图并未改变
// read-only
function computed<T>(
getter: (oldValue: T | undefined) => T,
// see "Computed Debugging" link below
debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>
2.创建一个可读可写的computed Ref
使用对象的形式,并传入getter函数和setter函数(二者皆必须)
<template>
<div>{{ name }}</div>
<button @click="name = 'aaa:bbb'">change name</button>
{{ fristName }}---{{ lastName }}
</template>
<script setup lang="ts">
const name = computed({
get() {
// 渲染
return fristName.value + ':' + lastName.value;
},
set(newVal) {
// 点击按钮赋值
[fristName.value, lastName.value] = newVal.split(':');
}
});
</script>
当点击按钮时,视图发生改变
// writable
function computed<T>(
options: {
get: (oldValue: T | undefined) => T
set: (value: T) => void
},
debuggerOptions?: DebuggerOptions
): Ref<T>
watch
1.使用watch侦听ref基本类型
<template>
<button
@click="
() => {
fristName = '我爱';
lastName = '中华';
}
"
>
change name
</button>
{{ fristName }}---{{ lastName }}
</template>
<script setup lang="ts">
import { watch, computed, ref } from 'vue';
const fristName = ref('ha');
const lastName = ref('kwan');
watch([fristName, lastName], (res) => {
// 只要有一个改变就会执行
console.log('watch', res);
});
</script>
监听基本类型的ref是可以侦听到新值和旧值的变化的
不需要开启第三个参数 { deep: true }
watch(
[fristName, lastName],
(newVal, oldVal) => {
console.log('newVal', newVal);
console.log('oldVal', oldVal);
},
);
2. 使用watch侦听ref引用类型
如果不开启deep,则无法侦听到属性值的变化,但是开启deep后,无法区分新值和旧值
<template>
<button @click="modifiedName">change name</button>
{{ fristName.name }}---{{ lastName.name }}
</template>
<script setup lang="ts">
import { watch, computed, ref, reactive } from 'vue';
const fristName = ref({ name: 'ha' });
const lastName = ref({ name: 'kwan' });
watch(
[fristName, lastName],
(newVal, oldVal) => {
console.log('newVal', newVal);
console.log('oldVal', oldVal);
},
{
deep: true
}
);
const modifiedName = () => {
fristName.value.name = '我爱';
lastName.value.name = '中华';
};
</script>
3. watch 侦听reactive类型的值
reactive可以被深度侦听(无需手动开启deep,默认开启,但是属性的层级比较深的时候还是需要手动深度监听)
但是依然无法区分新值和旧值!
<template>
<button @click="modifiedName">change name</button>
{{ fristName.name }}---{{ lastName.name }}
</template>
<script setup lang="ts">
import { watch, computed, ref, reactive } from 'vue';
const fristName = reactive({ name: 'ha' });
const lastName = reactive({ name: 'kwan' });
watch([fristName, lastName], (newVal, oldVal) => {
console.log('newVal', newVal);
console.log('oldVal', oldVal);
});
const modifiedName = () => {
fristName.name = '我爱';
lastName.name = '中华';
};
</script>
使用getter函数侦听单一属性,可以区分新值和旧值
watch(
() => fristName.name,
(newVal, oldVal) => {
console.log('newVal', newVal);
console.log('oldVal', oldVal);
}
);
watch(
() => [fristName.name, lastName.name],
(newVal, oldVal) => {
console.log('newVal', newVal);
console.log('oldVal', oldVal);
}
);
watchEffect
watchEffect接受一个回调函数,并在回调函数运行期间,自动收集响应式数据依赖。当某个依赖发生变化时,会重新执行回调函数(清理函数运行时机同useEffect)
注意,回调函数中收集依赖的过程是同步的,异步请求应该放在最后
watchEffect(async (cleanUp) => {
(a.value, b.value); // 如果有响应式数据依赖于某个异步函数,则可以提前收集依赖
c.value = await fetchApi(); // 如果c是不变的,就可以不用提出去
// do something with a, b;
} )
最后
本文只是简单举例了一下watch以及computed的使用和特性,希望能起到抛砖引玉的目的。
感谢朋友甩来的面试题
文章起名来自kimi(狗头)
转载自:https://juejin.cn/post/7418367838971756607