- 该文章是在学习 小满vue3 课程的随堂记录
- 示例均采用
,且包含
typescript
的基础用法
上一篇学习了 ref 全家桶,在此基础上一起学习下 reactive 全家桶
ref
可以接收 所有类型
,reactive
只能接收 object类型
(array、object、Map、Set)ref
在取值和赋值时都要通过 .value
,reactive不需要
reactive 不能直接整体赋值
,因为它是通过 proxy
创建的响应式对象,直接赋值会 破坏响应式
调用一些原生操作
,比如 数组可用 push、pop 等去修改外面再包上一层
import { reactive } from "vue";
// object类型
const form = reactive({
name: "xiaoman",
age: 18,
});
// array类型
const list = reactive<string[]>([]);
// 错误。直接整体赋值会破坏响应式
// list = ["a", "b", "c"];
// 可以通过原生方法去操作数据,不会破坏响应式
setTimeout(() => {
const res = ["jay chou", "jolin"];
list.push(...res);
}, 1000);
// 或者在外面包一层,这样对 obj.list 就可以整体赋值了
const obj = reactive<{ list: string[] }>({
list: [],
});
setTimeout(() => {
obj.list = ["a", "b", "c"];
}, 2000);
readonly 的值也会受影响
const info = reactive({
name: "xiaoman",
});
const rd = readonly(info);
// 设置为 readonly 后不可修改
// rd.name = 'daman'
// 但是可以修改它的源数据
info.name = "blue";
console.log("修改源数据,readonly的值也会受影响", info, rd);
可以看到,两者的值都被修改了:
shallowRef
十分相似,都是浅层的响应式修改深层
不会触发视图更新
const obj2 = reactive({
foo: {
bar: {
name: "xiaoman",
},
},
});
setTimeout(() => {
obj2.foo.bar.name = "blue222222222";
}, 1000);
const obj3 = shallowReactive({
foo: {
bar: {
name: "xiaoman",
},
},
});
setTimeout(() => {
obj3.foo = {
bar: {
name: "小满",
},
};
}, 1000);
setTimeout(() => {
// 修改深层不会触发更新
obj3.foo.bar.name = "blue3333333333";
console.log("obj3", obj3); // 打印成功,但是视图不会更新
}, 1000);
控制台:
视图:
setTimeout(() => {
// 修改深层不会触发更新
obj3.foo.bar.name = "blue3333333333";
console.log("obj3", obj3);
obj2.foo.bar.name = "blue555555"; // obj2 是 reactive,触发更新视图
}, 1000);
主要关注 createReactiveObject 函数的逻辑
/**
*
* 1、reactivity.d.ts中,关于 reactive 的类型定义:
*
* export declare function reactive(target: T): UnwrapNestedRefs;
*
* 其中 T extends object:即只能传入 object 的子类型
*
* 2、reactivity.cjs.prod.js中,
*
* function reactive(target) {
if (isReadonly(target)) {
return target;
}
.....
* 即:reactive 如果传入只读类型的,会直接返回
*
* 3、createReactiveObject 函数中,
* - 若传入的不是 object 类型,会抛出警告(dev环境)并直接返回;
* - 若传入的是被 proxy 代理过的(并且不是为了将其变为只读),也会直接返回
* - 如果能从缓存中找到,则直接返回(weakMap)
* - 如果在白名单中,也会直接返回,例如 __skip__(后面会讲的 markRaw 处理过的会加一个 __skip__,会跳过proxy代理 )
* - 如果以上条件都没触发,就会进行 proxy代理
*
*/