reactive API
function reactive (target) {
// 已经是一个 readonly proxy ,直接返回这个 只读响应式 proxy
if (target && target.__v_isReadonly) {
return target
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers)
}
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
//必须是对象或数组类型,返回target
if (!isObject(target)) {
return target
}
// target 已经是 Proxy 对象,直接返回
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// 查询readonlyMap和reactiveMap,是否存在其中。(所有的reactive和readonly都存在这两个里面)
const proxyMap = isReadonly ? readonlyMap : reactiveMap
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// 只能是指定的数据类型
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
// 根据对应的数据类型,使用不同的配置
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
// 放到对应的Map中
proxyMap.set(target, proxy)
return proxy
}
reactive创建流程
- 已经是一个 readonly proxy ,直接返回这个 proxy
- 必须是对象或数组类型,否则返回 target
- target 已经是 Proxy 对象,直接返回 Proxy。
- 查询readonlyMap和reactiveMap,是否存在其中。直接返回这个 proxy
- 只能是指定的数据类型,否则返回 target。Object、Array是1,Map、Set、WeakMap、WeakSet是2。去除了RegExp和Date
- 根据对应的数据类型,使用不同的配置。最后放到对应的Map中
readonly API
export function readonly<T extends object>(
target: T
): DeepReadonly<UnwrapNestedRefs<T>> {
return createReactiveObject(
target,
true,
readonlyHandlers,
readonlyCollectionHandlers
)
}
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
...
其他类型不看,就看Object、Array的。执行readonlyHandlers
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
...
}
readonlyHandlers
export const readonlyHandlers: ProxyHandler<object> = {
get: readonlyGet,
set(target, key) {
if (__DEV__) {
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
},
deleteProperty(target, key) {
if (__DEV__) {
console.warn(
`Delete operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
}
}
这里可以看到set和delete操作直接返回true。不对属性做任何修改操作,还报警告。
readonlyGet
const readonlyGet = createGetter(true)
function createGetter(isReadonly = false, shallow = false) {
return function get(target: Target, key: string | symbol, receiver: object) {
...
if (!isReadonly) {
track(target, TrackOpTypes.GET, key)
}
...
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
- readonly则不需要依赖收集 ,无法修改
- 如果属性有对象、数组的话,深度遍历全部修改为只读
ref API
reactive API 对传入的 target 类型有限制,必须是Object或者Array。基础类型(比如 String、Number、Boolean)是不支持的
想把基础数据类型变成响应式,要封装成一个对象太麻烦了。就有了ref API
const a = ref({value:1})
const b = shallowRef({})
a.value = '1111'
export function ref(value?: unknown) {
return createRef(value)
}
//判断一个变量是否是ref
function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true)
}
function createRef(rawValue: unknown, shallow = false) {
//已经是ref,直接返回rawValue
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
//私有变量_value,用来保存参数
private _value: T
//公用只读变量__v_isRef,标记对象是一个ref
public readonly __v_isRef = true
constructor(private _rawValue: T, public readonly _shallow = false) {
// 如果是对象或者数组类型,则转换一个 reactive 对象
this._value = _shallow ? _rawValue : isObject(val) ? reactive(val) : val
}
//访问value属性时,触发track 做依赖收集然后返回它的值
get value() {
track(toRaw(this), TrackOpTypes.GET, 'value')
return this._value
}
//修改value属性时,触发trigger 函数派发通知,修改_value
set value(newVal) {
if (hasChanged(toRaw(newVal), this._rawValue)) {
this._rawValue = newVal
this._value = this._shallow ? newVal : convert(newVal)
trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
}
}
}
- ref返回一个Object
- 如果 rawValue 已经是一个ref,返回 rawValue
- 如果 rawValue 是一个Object,对 rawValue 进行reactive操作
- 使用 shallowRef ,不对 rawValue 进行reactive操作
细说说ref
ref 与 reactive 不同的是。 reactive返回的是一个proxy,ref返回的是一个对象
const a = ref(1);
{
//标记是否是isRef
__v_isRef: true
//私有变量,用来存储传入的实参
_rawValue: 1
_shallow: false
//私有变量,用来存储传入的实参
_value: 1
//访问的value值
__proto__: {
value: 1
}
}
_rawValue和_value的区别
_rawValue保存传入实参
_value如果传入的是对象,且使用的是ref而不是shallowRef。_value 保存的就是 reactive 的 Proxy
__v_isRef
const a = ref({ __v_isRef: true, a: 1 });
如果你这么创建一个ref,那么会直接返回这个 target不进行任何操作。
| reactive | readonly | ref | |
|---|---|---|---|
| 参数 | Object、Array、Map、Set、WeakMap、WeakSet | Object、Array、Map、Set、WeakMap、WeakSet | 任意值 |
| 只读 | 可修改 | 只读 | 可修改 |
| 返回值 | Proxy | Proxy | Object |
reactive 和 ref 区别就在于参数的属性,reactive只能使用Object、Array、Map、Set、WeakMap、WeakSet,而ref可以使用任意值而且如果参数是Object也会对参数进行reactive