export function ref<T extends object>(
value: T
): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
// value 参数即为我们传进来的值
export function ref(value?: unknown) {
return createRef(value, false) //调用createRef,并将参数传递进去
}
首先我们来看ref 的函数定义,上面的都是进行函数重载,主要看最下面的。
函数内部仅调用了createRef(value,false)。
// 接收参数 rawValue, shallow, shallow即是否创建shallowRef
function createRef(rawValue: unknown, shallow: boolean) {
//判断rawValue是否为ref,是则直接返回
if (isRef(rawValue)) {
return rawValue
}
//创建RefImpl类实例,并返回
return new RefImpl(rawValue, shallow)
}
这里的逻辑很简单,判断是否为ref 是则返回,否则创建RefImpl 实例并返回
// RefImpl 类
class RefImpl<T> {
private _value: T //值(私有)
private _rawValue: T //原始值(私有)
public dep?: Dep = undefined //副作用函数
public readonly __v_isRef = true //标记是ref
//构造方法,接收泛型value,以及boolean类型只读_shallow
constructor(value: T, public readonly _shallow: boolean) {
//_shallow为true,则直接把 value 赋值给 _rawValue 与 _value, 否则进行toRaw,toReactive转换
this._rawValue = _shallow ? value : toRaw(value)
this._value = _shallow ? value : toReactive(value)
}
get value() {
trackRefValue(this) //收集依赖(订阅)
return this._value
}
set value(newVal) {
newVal = this._shallow ? newVal : toRaw(newVal)
// hasChanged 判断是否变更,来源于shared工具函数,内部调用 Object.is进行对比
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = this._shallow ? newVal : toReactive(newVal)
triggerRefValue(this, newVal) //触发依赖(发布)
}
}
}
在RefImpl类中,constructor对 _value 与 _rawValue进行赋值,get value() 收集依赖,set value() 触发依赖
当开发时,state.value 返回的则是值 _value, 如果ref() 传进一个对象在toReactive时会进行reactive() 转换,此时 _value 为 Proxy 响应式对象。
顺便贴下 hasCHanged实现,来源shared工具函数。
export const hasChanged = (value: any, oldValue: any): boolean =>
!Object.is(value, oldValue)
export function trackRefValue(ref: RefBase<any>) {
// isTracking() 判断是否可进行依赖收集,此方法在 effect.ts 中,后续相关文章会介绍
if (isTracking()) {
ref = toRaw(ref) //获取原始值
// dep不存在则创建( 刚创建的RefImpl的dep值为undefined )
if (!ref.dep) {
//创建dep,此方法在 dep.ts 中后续相关文章会介绍
// 简单介绍一下,dep就是一个 new Set()用于收集依赖(副作用),
// 此外还有dep.w,dep.n 用于对依赖收集的重复与嵌套进行优化处理
ref.dep = createDep()
}
// trackEffects 真正的收集依赖方法,此方法在 effect.ts 中,后续相关文章会介绍
if (__DEV__) {
//dev环境中传入一些便于调试的参数
trackEffects(ref.dep, {
target: ref,
type: TrackOpTypes.GET,
key: 'value'
})
} else {
trackEffects(ref.dep)
}
}
}
可以看到trackRefValue 主要作用就是对RefImpl.dep进行初始化赋值。
因为只有当 RefImpl.get() 触发时(例: state.value),才会 trackRefValue 来对dep进行初始化(new Set()),所以当 **RefImpl.get()**没有被触发(例: 从未使用到state.value),则不进行dep初始化,优化节省空间。
export function triggerRefValue(ref: RefBase<any>, newVal?: any) {
ref = toRaw(ref) //获取原始值
if (ref.dep) {
// triggerEffects 真正的触发依赖方法,此方法在 effect.ts 中,后续相关文章会介绍
if (__DEV__) {
//dev环境中传入一些便于调试的参数
triggerEffects(ref.dep, {
target: ref,
type: TriggerOpTypes.SET,
key: 'value',
newValue: newVal
})
} else {
triggerEffects(ref.dep)
}
}
}
很简单,判断dep是否存在,是则触发依赖
export function shallowRef<T extends object>(
value: T
): T extends Ref ? T : ShallowRef<T>
export function shallowRef<T>(value: T): ShallowRef<T>
export function shallowRef<T = any>(): ShallowRef<T | undefined>
export function shallowRef(value?: unknown) {
return createRef(value, true)
}
与ref区别就在于 createRef 时 _shallow 为 true,表式创建浅层ref,即不走toRaw与 toReactive, 所以当传入值为对象时,_value 为普通对象,所以当修改对象某个属性时,不会触发副作用,例如修改state.value.age 不会触发副作用,只有修改state.value 时才会触发副作用
//判断是否为ref,如果是RefImpl实例则__v_isRef为true
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true)
}
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K
): ToRef<T[K]>
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue: T[K]
): ToRef<Exclude<T[K], undefined>>
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue?: T[K]
): ToRef<T[K]> {
const val = object[key]
return isRef(val)
? val
: (new ObjectRefImpl(object, key, defaultValue) as any)
}
从object去除key对应value,如果是ref类型则直接返回,否则调用new ObjectRefImpl创建实例并返回, 我们来看一下ObjectRefImpl类
class ObjectRefImpl<T extends object, K extends keyof T> {
public readonly __v_isRef = true
constructor(
private readonly _object: T,
private readonly _key: K,
private readonly _defaultValue?: T[K]
) {}
get value() {
const val = this._object[this._key]
return val === undefined ? (this._defaultValue as T[K]) : val
}
set value(newVal) {
this._object[this._key] = newVal
}
}
构造函数进行初始赋值,get value() 则返回 _object 对应值,当 _object 为响应式对象时如reactive 则收集依赖,如果为undefined则返回创建实例时传入的默认值, set value() 时,如果 _object 为响应式对象时,则触发依赖。
export function toRefs<T extends object>(object: T): ToRefs<T> {
//dev环境中不允许传进来非isProxy对象
if (__DEV__ && !isProxy(object)) {
console.warn(`toRefs() expects a reactive object but received a plain one.`)
}
//对 array类型做处理
const ret: any = isArray(object) ? new Array(object.length) : {}
//遍历object对每个值进行toRef转换
for (const key in object) {
ret[key] = toRef(object, key)
}
return ret
}
可以看出,toRefs就是把oject响应式对象中的每个属性对应的值进行toRef转换,并返回ret结果对象
export function unref<T>(ref: T | Ref<T>): T {
return isRef(ref) ? (ref.value as any) : ref
}
如果是ref则返回对应值value,否则返回本身
export function proxyRefs<T extends object>(
objectWithRefs: T
): ShallowUnwrapRef<T> {
return isReactive(objectWithRefs)
? objectWithRefs
: new Proxy(objectWithRefs, shallowUnwrapHandlers)
}
判断是否为 reactive, 是则返回,否则创建Proxy对象并返回,我们来看一下shallowUnwrapHandlers
const shallowUnwrapHandlers: ProxyHandler<any> = {
//get时调用unref返回 ref.value实际值
get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),
set: (target, key, value, receiver) => {
const oldValue = target[key]
if (isRef(oldValue) && !isRef(value)) {
//当旧值为ref类型且新值不为ref类型时,对oldValue.value 进行赋值
oldValue.value = value
return true
} else {
//否则正常返回
return Reflect.set(target, key, value, receiver)
}
}
}
当执行oldValue.value = value, get的时候则直接拿到oldValue.value
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
return new CustomRefImpl(factory) as any
}
创建CustomRefImpl实例并返回,有必要放一下factory的类型定义。
export type CustomRefFactory<T> = (
track: () => void,
trigger: () => void
) => {
get: () => T
set: (value: T) => void
}
接收 track(收集依赖),与trigger(触发依赖),返回带有get函数和set函数的对象
我们接着看 CustomRefImpl 类。
class CustomRefImpl<T> {
public dep?: Dep = undefined
private readonly _get: ReturnType<CustomRefFactory<T>>['get']
private readonly _set: ReturnType<CustomRefFactory<T>>['set']
public readonly __v_isRef = true
constructor(factory: CustomRefFactory<T>) {
//执行factory函数是,传入 trackRefValue, triggerRefValue
// 这里用 ()=>trackRefValue(this),是为了解决用户在调用时的this指向问题
const { get, set } = factory(
() => trackRefValue(this),
() => triggerRefValue(this)
)
this._get = get
this._set = set
}
get value() {
return this._get()
}
set value(newVal) {
this._set(newVal)
}
}
与RefImpl实现其实差不多,同样是使用 trackRefValue 与 triggerRefValue 去做依赖收集触发,只不过get() 与set() 方法可由用户自定义,可以控制值得操作以及什么时候去做依赖的收集与触发。使用时,customRef(fn) 这里的fn就是factory(工厂), 由类型定义可知必须实现get() 与set(value) 方法, 并且接收 track(trackRefValue依赖收集) 与 trigger(triggerRefValue触发依赖)。
//手动触发 ref 对应依赖(副作用)
export function triggerRef(ref: Ref) {
triggerRefValue(ref, __DEV__ ? ref.value : void 0)
}
传进ref,触发对应依赖,在vue文档中搭配shallowRef使用。
一些定义,函数中会用到,自己看哈哈哈
export const enum ReactiveFlags {
SKIP = '__v_skip',
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
RAW = '__v_raw'
}
export interface Target {
[ReactiveFlags.SKIP]?: boolean
[ReactiveFlags.IS_REACTIVE]?: boolean
[ReactiveFlags.IS_READONLY]?: boolean
[ReactiveFlags.RAW]?: any
}
export const reactiveMap = new WeakMap<Target, any>()
export const shallowReactiveMap = new WeakMap<Target, any>()
export const readonlyMap = new WeakMap<Target, any>()
export const shallowReadonlyMap = new WeakMap<Target, any>()
const enum TargetType {
INVALID = 0,
COMMON = 1,
COLLECTION = 2
}
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// 如果为只读代理,则直接返回, ReactiveFlags.IS_READONLY 值为 '__v_isReadonly'
// if trying to observe a readonly proxy, return the readonly version.
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers, // ProxyHandler 的一种,专门用来处理 reactive, 来源 baseHandlers
mutableCollectionHandlers, // ProxyHandler 的一种,专门用来处理 reactive,来源 collectionHandlers
reactiveMap // new WeakMap()
)
}
如果已为只读代理对象,则直接返回,否则调用 createReactiveObject
// target 参数 为传进来的值
// isReadonly 是否只读
// baseHandlers 基本处理函数(target为 Object, Array时使用)
// collectionHandlers 集合处理函数(target为 Map,WeakMap, Set, WeakSet 时使用)
// proxyMap 用来存储target对应的proxy,做缓存效果
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
//判断是否为对象类型,是则直接返回
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// target是响应式对象 && !(创建只读 && target是 reactive)
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// 尝试从代理集合中获取target对应的代理对象proxy,如果存在则直接返回
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// 获取target类型,只有在白名单中的类型才可进行proxy代理,否则直接返回
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
//创建proxy实例
const proxy = new Proxy(
target,
//类型是集合类的,则采用 collectionHandlers, 相反采用 baseHandlers
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
//向proxyMap中存储target对应的proxy对象
proxyMap.set(target, proxy)
return proxy
}
这里我把 白名单 列举出来 (Object,Array,Map,Set,WeakMap,WeakSet)
可以看到 createReactiveObject 中对各种边界进行处理,以及对target 转换后的 proxy 进行了缓存处理,重复reactvice(target) 时, 可以减少不必要的操作。
function getTargetType(value: Target) {
//tip: Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
? TargetType.INVALID // 0
: targetTypeMap(toRawType(value)) //toRawType 来源shared工具函数
}
当 value.__v_skip 为true 或 不可扩展,则返回 TargetType.INVALID , 代表无效
否则调用 targetTypeMap 获取对应type
顺便贴下 toRawType
//获取数据类型, toTypeString 中实际调用的是,Object.prototype.toString.call()
export const toRawType = (value: unknown): string => {
return toTypeString(value).slice(8, -1)
}
function targetTypeMap(rawType: string) {
switch (rawType) {
case 'Object':
case 'Array':
return TargetType.COMMON // 1
case 'Map':
case 'Set':
case 'WeakMap':
case 'WeakSet':
return TargetType.COLLECTION // 2
default:
return TargetType.INVALID //0
}
}
很简单,传入类型,判断获取TargetType对应的枚举值
export function readonly<T extends object>(
target: T
): DeepReadonly<UnwrapNestedRefs<T>> {
return createReactiveObject(
target,
true, //标记只读
readonlyHandlers, // ProxyHandler 的一种,专门用来处理 readonly, 来源 baseHandlers
readonlyCollectionHandlers, //ProxyHandler 的一种,专门用来处理 readonly, 来源 collectionHandlers
readonlyMap
)
}
export const toReactive = <T extends unknown>(value: T): T =>
isObject(value) ? reactive(value) : value
逻辑很简单,对传进来的value 进行判断,如果是对象类型则进行reactive转换,否则直接返回
顺便贴一下isObject实现,来源shared工具函数
export const isObject = (val: unknown): val is Record<any, any> =>
val !== null && typeof val === 'object'
//判断是否为reactive
export function isReactive(value: unknown): boolean {
//判断是否为 readonly
if (isReadonly(value)) {
// ReactiveFlags.RAW = '__v_raw'
return isReactive((value as Target)[ReactiveFlags.RAW])
}
// ReactiveFlags.IS_REACTIVE= '__v_isReactive'
return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
}
如果为readonly,则重调 isReactive, 应对使用该api时,从响应式对象中创建只读proxy
const state = reactive({ name: ‘John’ })
const stateCopy = readonly(state)
如果是响应式对象,value.__v_isReactive 会返回创建get方法时(调用createGetter),传入的isReadonly参数, 取反返回,对应 shallowReactiveHandlers,mutableHandlers 则传入为 false或不传。
export function isReadonly(value: unknown): boolean {
// ReactiveFlags.IS_READONLY = __v_isReadonly
return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
}
如果是响应式对象,value.__v_isReadonly 会返回创建get方法时(调用createGetter),传入的isReadonly参数,对应 readonlyHandlers ,shallowReadonlyHandlers 则传入为 true。
export function isProxy(value: unknown): boolean {
return isReactive(value) || isReadonly(value)
}
判断是否为 reactive 或 readonly
export function shallowReactive<T extends object>(
target: T
): ShallowReactive<T> {
return createReactiveObject(
target,
false,
shallowReactiveHandlers, // ProxyHandler 的一种,专门用来处理 shallowReactive, 来源 baseHandlers
shallowCollectionHandlers, // ProxyHandler 的一种,专门用来处理 shallowReactive, 来源 collectionHandlers
shallowReactiveMap
)
}
与reactive 区别在于使用了 shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap
export function shallowReadonly<T extends object>(
target: T
): Readonly<{ [K in keyof T]: UnwrapNestedRefs<T[K]> }> {
return createReactiveObject(
target,
true,
shallowReadonlyHandlers, // ProxyHandler 的一种,专门用来处理 shallowReadonly, 来源 baseHandlers
shallowReadonlyCollectionHandlers, // ProxyHandler 的一种,专门用来处理 shallowReadonly, 来源 collectionHandlers
shallowReadonlyMap
)
}
与readonly 区别在于使用了 shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap
//标记一个对象,使其永远不会转换为 proxy。返回对象本身。
export function markRaw<T extends object>(value: T): T {
// def 来源于 shared工具函数
// ReactiveFlags.SKIP = '__v_skip'
def(value, ReactiveFlags.SKIP, true)
return value
}
通过def给value定义一个 __v_skip 不可写并为true的值
这个 __v_skip 会在 createReactiveObject 的 getTargetType 中 被使用作为判断
顺便贴下def实现
export const def = (obj: object, key: string | symbol, value: any) => {
Object.defineProperty(obj, key, {
configurable: true,
enumerable: false,
value
})
}
//获取原始值
export function toRaw<T>(observed: T): T {
// ReactiveFlags 是一个枚举类型 RAW 值为 '__v_raw'
const raw = observed && (observed as Target)[ReactiveFlags.RAW]
return raw ? toRaw(raw) : observed
}
可以看到,如果 observed.__v_raw取值为false,toRaw则返回observed
这里用 __v_raw 获取是因为在响应式proxy对象的get方法中,对获取该key做了处理来返回原始值target。在这里放个截图
这篇其实更像是对api的实现进行解析,如果有写的不好的地方欢迎指正,谢谢大家。