目录
- reactive、ref、toRef、toRefs 使用与区别
- reactive
- ref 作用及用法
- toRef 作用及用法
- toRefs 作用及用法
- ref,toRef,toRefs 源码实现解析详细注释
reactive、ref、toRef、toRefs 使用与区别
reactive
- 参数传入普通对象,不论层级多深都可以返回响应式对象,(参数只能是对象)
- 但是解构、扩展运算符会失去响应式
ref 作用及用法
- 参数可以为任意类型,推荐使用基本类型
- 使用时 需要通过
xxx.value
的形式获取 - 本质是
拷贝粘贴
一份数据,脱离了与源数据的交互 - 将对象中属性变成响应式数据,修改该数据是不会影响到源数据,但是会更新视图
{{ refTest }}
toRef 作用及用法
- 针对 reactive 解构失去响应式的问题,创建了 toRef,用于为源响应式对象上的属性新建一个 ref,保持对源对象属性的响应式交互。
- 语法:
toRef(target, key)
- 使用时 需要通过
xxx.value
的形式获取 - 本质是引用,与源数据有交互,修改该数据是会影响源数据,但是不会更新视图,如果需要更新视图,需要使用 reactive 包裹源数据
{{ toRefTest }}
{{ toRefReactTest }}
toRefs 作用及用法
- 就是批量的 toRef 操作,toRefs 是一次性将 reactive 中的所有属性都转为 ref
- 语法:
toRefs(target)
- 同样可以用于解构 reactive 的响应式对象
- 使用时 需要通过
xxx.value
的形式获取 - 本质是引用,与源数据有交互,修改该数据是会影响源数据,但是不会更新视图,如果需要更新视图,需要使用 reactive 包裹源数据
普通对象:{{ name }} -- {{ age }}
reactive对象:{{ rename }} -- {{ reage
}}
ref,toRef,toRefs 源码实现解析详细注释
ref 和 reactive 的底层原理区别: reactive 内部采用 proxy ,而 ref 中内部采用的是 defineProperty
ref、shallowRef 源码实现。使用class RefImpl
实现,会被 babel 编译成defineProperty
其中 share.ts 和 reactive.ts 文件中的方法,不在赘述,详见上一篇 响应式原理的文章
import { hasChanged, isArray, isObject } from "./shared";
import { TrackOpTypes, TriggerOrTypes } from "./shared";
import { track, trigger } from "./effect";
import { reactive } from "./reactive";
export function ref(value) {
return createRef(value);
}
// shallowRef 只能处理基本类型数据
export function shallowRef(value) {
return createRef(value, true);
}
const convert = (val) => (isObject(val) ? reactive(val) : val);
class RefImpl {
public _value;
public __v_isRef = true; // 实例添加 __v_isRef, 表示是一个ref属性
constructor(public rawValue, public shallow) {
// 1.参数前面加修饰符 表示实例属性
this._value = shallow ? rawValue : convert(rawValue); // 如果是深度监听 需要把里面的都变成响应式的
}
// 2. 类的属性访问器
get value() {
// 3. 依赖收集 代理取值取_value
track(this, TrackOpTypes.GET, "value"); // 依赖收集
return this._value;
}
set value(newValue) {
// 4. 判断老值和新值是否有变化
if (hasChanged(newValue, this.rawValue)) {
this.rawValue = newValue; // 新值会作为老值
this._value = this.shallow ? newValue : convert(newValue);
// 5. 触发更新
trigger(this, TriggerOrTypes.SET, "value", newValue);
}
}
}
function createRef(rawValue, shallow = false) {
return new RefImpl(rawValue, shallow);
}
toRef,toRefs 源码实现。使用class ObjectRefImpl
实现,会被 babel 编译成defineProperty
class ObjectRefImpl {
public __v_isRef = true; // 实例添加 __v_isRef, 表示是一个ref属性
constructor(public target, public key) {}
get value() {
return this.target[this.key]; // 如果原对象是响应式的就会依赖收集
}
set value(newValue) {
this.target[this.key] = newValue; // 如果原来对象是响应式的 那么就会触发更新
}
}
// 将对象的某一个值转化成 ref类型
export function toRef(target, key) {
return new ObjectRefImpl(target, key);
}
// 可能传递的是一个数组 或者对象,属性全部转化成 ref类型
export function toRefs(object) {
const ret = isArray(object) ? new Array(object.length) : {};
for (let key in object) {
ret[key] = toRef(object, key); // 遍历调用toRef方法
}
return ret;
}