- 该文章是在学习 小满vue3 课程的随堂记录
- 示例均采用
<script setup>
,且包含typescript
的基础用法
前言
上一篇学习了 ref 全家桶,在此基础上一起学习下 reactive 全家桶
一、reactive 对比 ref
ref
可以接收所有类型
,reactive
只能接收object类型
(array、object、Map、Set)ref
在取值和赋值时都要通过.value
,reactive不需要
reactive 不能直接整体赋值
,因为它是通过proxy
创建的响应式对象,直接赋值会破坏响应式
- 解决方案 1:可以
调用一些原生操作
,比如 数组可用 push、pop 等去修改 - 解决方案 2:
外面再包上一层
- 解决方案 1:可以
① 创建
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);
二、将 reactive 的值 设置为 readonly
- 设置为 readonly 后不可修改
- 修改 reactive 源数据,
readonly 的值也会受影响
const info = reactive({name: "xiaoman",
});
const rd = readonly(info);// 设置为 readonly 后不可修改
// rd.name = 'daman'// 但是可以修改它的源数据
info.name = "blue";
console.log("修改源数据,readonly的值也会受影响", info, rd);
可以看到,两者的值都被修改了:
三、shallowReactive
- 与上一篇 ref 全家桶 中
shallowRef
十分相似,都是浅层的响应式 - 修改第一层会触发视图更新,
修改深层
不会触发视图更新
- 有其他触发视图更新的操作,也会顺带将其更新
① reactive 是深层的响应式,视图会立刻更新
const obj2 = reactive({foo: {bar: {name: "xiaoman",},},
});
setTimeout(() => {obj2.foo.bar.name = "blue222222222";
}, 1000);
② shallowReactive 是浅层的响应式
const obj3 = shallowReactive({foo: {bar: {name: "xiaoman",},},
});
1、修改浅层才会触发响应式,会立刻更新:
setTimeout(() => {obj3.foo = {bar: {name: "小满",},};
}, 1000);
2、修改深层可以打印到新值,但视图不会立刻更新:
setTimeout(() => {// 修改深层不会触发更新obj3.foo.bar.name = "blue3333333333";console.log("obj3", obj3); // 打印成功,但是视图不会更新
}, 1000);
控制台:
视图:
3、会被其他有视图更新的操作,顺带着一起更新掉
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<T extends object>(target: T): UnwrapNestedRefs<T>;* * 其中 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代理**/