1. ref 源码实现
由于reactive只能代码对象,不能支持原始类型,所以vue3提供了一个ref方法方便我们对原始值进行处理;
1.1 ref API使用
import { effect, ref } from "@hpstream/reactivity";
const flag = ref(false);
const nums = ref(1);
const str = ref('1');
effect(() => {
document.body.innerHTML = flag.value ? "30" : "hp";
});
setTimeout(() => {
flag.value = true;
}, 1000);
1.2 源码实现:
tof是对于reactive的一个包装,通过get value,和set value的调用reactive,进行依赖收集和分发。
function toReactive(value) {
// 将对象转化为响应式的
return isObject(value) ? reactive(value) : value;
}
class RefImpl {
public __v_isRef = true;
public _value;
public deps = new Set();
constructor(public rawValue) {
this._value = toReactive(rawValue);
}
get value() {
trackEffects(this.deps);
return this._value;
}
set value(newVal) {
if (this._value != newVal) {
this._value = toReactive(newVal);
triggerEffects(this.deps);
}
}
}
export function ref(source) {
return new RefImpl(source);
}
我们如果理解了reactive和vue3依赖收集的实现,剩下的只是在之前的基础上增加了一些好用的api; 所以代码写起来也会比较简单。
2. toRef 与 toRefs源码类型;
将reactive类型,转换成ref的类型
2.1 toRef API 使用
import { effect, toRefs, toRef, reactive } from "@hpstream/reactivity";
const state = reactive({ name: "jw", age: 30 });
let person = toRefs(state); // 解构的时候将所有的属性都转换成ref即可
let name = toRef(state, "name");
effect(() => {
document.body.innerHTML =
person.name.value + "今年" + person.age.value + "岁了";
});
setTimeout(() => {
name.value = 31;
}, 1000);
reactive 转换成toRef,本质上也是对reactive进行了一个包装。
2.2 toRef 源码实现;
class ObjectRefImpl {
constructor(private source, private key: string) {}
get value() {
return this.source[this.key];
}
set value(newVal) {
if (this.source[this.key] !== newVal) {
this.source[this.key] = toReactive(newVal);
}
}
}
export function toRef(source, key: string) {
return new ObjectRefImpl(source, key);
}
纯粹用set,get做了一层代码,去操作reactive;
2.3 toRefs的实现
循环调用toRefs就可以实现了。
export function toRefs<T>(
source: T
): T extends any[] ? ObjectRefImpl[] : Record<keyof T, ObjectRefImpl> {
if (Array.isArray(source)) {
let result: any = [];
for (let item of source) {
result.push(item);
}
return result;
} else {
let result: any = {};
for (let key in source) {
result[key] = toRef(source, key);
}
return result;
}
}
致谢
如果感觉我的文章有用,请关注下我的公众号: 前端小黄。 我将不定期更新我的原创文章。
本文章源码地址:github.com/hpstream/vu…;