目录
1.ref基本实现
2.toRef基本实现
3.toRefs基本实现
4.proxyRefs基本实现
ref函数接收一个一个值,如果这个值是基础数据类型,则直接返回一个RefImpl对象,并对这个对象设置属性访问器和属性修改器,在其中进行对应的依赖收集和触发更新
如果接受一个复杂类型的数据,则会将数据包装成一个RefImpl对象,并将其value值通过reactive进行代理,最后设置给RefImpl对象。
1. 创建ref.ts 文件,在文件中导出一个函数ref,并在index。ts中统一导出
# ref.ts
export function ref(value) {
return createRef(value) // 创建一个Ref对象并返回
}
2. 实现createRef函数
function createRef(value) {
return new RefImpl(value)
}
class RefImpl {
__v_isRef = true // 标识当前变量是否是ref对象
_value // 存储ref对象的值
dep = [] // 用于收集依赖
constructor(public rawValue) {
// 判断是否是对象,如果是对象则递归ref
this._value = toReactive(rawValue) // 将对对象代理,将普通值原封不动返回
}
get value() {
return this._value // 返回ref对象的值
}
set value(newValue) {
if(newValue !== this._value) {
this._value = newValue // 更新ref对象的值
this.rawValue = newValue // 更新ref对象的原始值
}
}
}
# reactive.ts
export function toReactive(value) {
return isObject(value) ? reactive(value) : value
}
```
3. 收集依赖并触发更新
# ref.ts
import { currentEffect, trackEffect, triggerEffect } from "./effect"
import { toReactive } from "./reactive"
import { createDep } from "./reactiveEffect"
class RefImpl {
...
get value() {
...
trackrRefValue(this) // 收集依赖
...
}
set value(newValue) {
...
triggerRefValue(this) // 触发依赖
}
}
function trackrRefValue(ref) {
// 判断当前需要收集的依赖是否存在
if(currentEffect) {
// 收集依赖,并创建一个以当前ref为key的依赖表
trackEffect(currentEffect,ref.dep = createDep(() => ref.dep = undefined,"undefined"))
}
}
function triggerRefValue(ref) {
// 触发更新
let dep = ref.dep // 提取当前ref的依赖表
if(dep) {
triggerEffect(dep) // 触发依赖表
}
}
在我们书写代码时,有可能会遇到下面这种状况
const user = reactive({
name: "zhangsan",
age: 18
})
const { name,age } = user
如上,我们对一个reactive响应式对象进行了结构,这个操作在本质上会破坏proxy对象的代理,让响应式对象失去响应式特性,因此就有了toRef函数,专门用于将reactive对象中的某个属性结构出来并转换成ref对象。
该函数需要接受两个参数,第一个参数是reactive对象,第二个参数是reactive对象的属性key。返回一个ref对象,该对象的value属性就是reactive对象中key对应的值。并且支持响应式
1. 创建toRef函数
# ref.ts
export function toRef(reactive,key) {
return new ObjectRefImpl(reactive,key)
}
2. 实现ObjectRefImpl类
class ObjectRefImpl {
__v_isRef = true // 标识当前变量是否是ref对象
constructor(public _object, public _key) {
}
get value() {
return this._object[this._key] // 返回对象的值
}
set value(newValue) {
this._object[this._key] = newValue // 更新对象的值
}
}
toRefs函数用于将reactive对象中的所有属性都转换成ref对象,并且返回一个包含所有ref对象的proxy对象。
1. 创建toRefs函数
export function toRefs(reactive) {
const res = {}
for(const key in reactive) {
res[key] = toRef(reactive, key)
}
return res
}
这个api主要用于在模板渲染时将所有的ref对象都代理成Proxy,在每次读取ref对象的属性值时,直接将其的value属性返回,这样在每次使用时就不需要再.value调用了。
1. 创建proxyRefs函数
export function proxyRefs(objectWithRefs) {
return new Proxy(objectWithRefs, {
get(target,key,receiver) {
let r = Reflect.get(target,key,receiver)
return r.__v_isRef ? r.value : r // 自动将value去掉包裹
},
set(target,key,value,receiver) {
const oldValue = target[key]
// 如果oldValue是ref对象,则更新ref对象的值
if(oldValue && oldValue.__v_isRef) {
oldValue.value = value // 更新ref对象的值
return true
} else {
// 如果oldValue不是ref对象,则更新对象的值
return Reflect.set(target,key,value,receiver) // 更新对象
}
}
})
}