上一篇文章说了一下reactive的相关信息,这一节来看看Vue 3中ref的使用方法及相关信息react
附上一篇文章连接:juejin.im/post/5d99de…bash
为了理解ref的逻辑顺序,就直接从ref核心函数一步一步扩展讲解吧~函数
export function ref<T>(raw: T): Ref<T> {
raw = convert(raw)
const v = {
_isRef: true,
get value() {
track(v, OperationTypes.GET, '')
return raw
},
set value(newVal) {
raw = convert(newVal)
trigger(v, OperationTypes.SET, '')
}
}
return v as Ref<T>
}复制代码
首先,声明了一个ref,该函数类型为Ref类型,Ref<T>是一个接口,源码以下:post
export interface Ref<T> {
_isRef: true
value: UnwrapNestedRefs<T>
}复制代码
ref的核心就是判断_isRef是否为true,value值则是存放数据的地方ui
UnwrapNestedRefs是在判断T(类型)若是是继承了Ref则使用当前类型,若是不是,使用UnwrapRef类型,源码以下:spa
export type UnwrapNestedRefs<T> = T extends Ref<any> ? T : UnwrapRef<T>复制代码
UnwrapRef的做用就是当遇到嵌套Ref的时候能正确(使用递归)推出业务数据的类型
code
注:Vue 源码中手动写了递归解析案例对象
⭐因手动写的案例代码多,仅截取前两段代码(未截取的代码都是相似)继承
export type UnwrapRef<T> = T extends Ref<infer V>
? UnwrapRef2<V>
: T extends Array<infer V>
? Array<UnwrapRef2<V>>
: T extends BailTypes
? T
: T extends object ? { [K in keyof T]: UnwrapRef2<T[K]> } : T
type UnwrapRef2<T> = T extends Ref<infer V>
? UnwrapRef3<V>
: T extends Array<infer V>
? Array<UnwrapRef3<V>>
: T extends BailTypes
? T
: T extends object ? { [K in keyof T]: UnwrapRef3<T[K]> } : T复制代码
注:可以递归解析的类型只有ref类型,Array和Object,若是是bailTypes中的类型,则中止递归
bailTypes源码:
type BailTypes =
| Function
| Map<any, any>
| Set<any>
| WeakMap<any, any>
| WeakSet<any>复制代码
回到ref的源码,介绍了Ref接口以后,接下来就是对传入的参数进行处理
传入的参数会被传入convert中进行处理,源码以下:
const convert = (val: any): any => (isObject(val) ? reactive(val) : val)复制代码
即,若是是对象(复杂类型、多层)会将传入的值交由reactive作响应式处理,不是对象,则返回传入的值
接下来建立一个v对像,其中传入_isRef:true(以前说过判断是否未ref类型的关键就是isRef)
判断isRef的源码以下:
export function isRef(v: any): v is Ref<any> {
return v ? v._isRef === true : false
}复制代码
接着就是v中的get和set方法
const v = {
_isRef: true,
get value() {
track(v, OperationTypes.GET, '')
return raw
},
set value(newVal) {
raw = convert(newVal)
trigger(v, OperationTypes.SET, '')
}
}复制代码
get方法中有一个track方法,track的做用就是监听并收集依赖
set方法中就是用convert将newVal值转换为响应式赋值给raw,trigger的做用就是执行函数
注:上面的Convert中对于将复杂类型(Object)利用reactive转为响应式,而对于简单类型数据则没有进行相关处理,是由于当咱们在将参数在函数中传递或者解构参数时,会丢失原始数据的引用,所以(如上图v对象所示),直接用set和get方法对值进行拦截就能够,而不用再采起Proxy来进行拦截处理
另外,Vue 还提供了一个toRefs的方法,将传入的对象的key分别存入v对象,将_isRef设置为true,接着将处理后的key赋值给一个新对象ret
源码以下:
export function toRefs<T extends object>(
object: T
): {[K in keyof T]: Ref<T[K]> } {
const ret: any = {}
for (const key in object) {
ret[key] = toProxyRef(object, key)
}
return ret
}
function toProxyRef<T extends object, K extends keyof T>(
object: T, key: K
): Ref<T[K]> {
const v = {
_isRef: true,
get value() {
return object[key]
},
set value(newVal) {
object[key] = newVal
}
}
return v as Ref<T[K]>
}复制代码
ref的相关介绍就到这里拉~,这是我本身对Vue 3中ref的一些理解,若是哪里有错误的,感谢你们指出拉~~