Reactive有那些可用的函数:
export {
reactive,
readonly,
isReactive,
isReadonly,
isProxy,
shallowReactive,
shallowReadonly,
markRaw,
toRaw,
ReactiveFlags, // 是type
DeepReadonly, // 是type
ShallowReactive, // 是type
UnwrapNestedRefs // 是type
} from './reactive'
type和枚举
const enum ReactiveFlags {
SKIP = '__v_skip',
IS_REACTIVE = "__v_isReactive",
IS_READONLY = "__v_isReadonly",
RAW = "__v_raw",
}
// 这三个都是用做type,就不讲了,有兴趣的去看一下代码呗
DeepReadonly,
ShallowReactive,
UnwrapNestedRefs
公共的部分(后续很多地方要回到这)
1、生成get、set
const get = createGetter();
const set = createSetter();
2、createGetter、createSetter
createGetter接受两个参数:1、不可修改;2、浅代理
下面代码有三个重点,已经标注,后续很多api会用到。
function createGetter(isReadonly = false, shallow = false) {
return function get(target, key, receiver) {
//** 重点一**
const isExistInReactiveMap = () =>
key === ReactiveFlags.RAW && receiver === reactiveMap.get(target);
const isExistInReadonlyMap = () =>
key === ReactiveFlags.RAW && receiver === readonlyMap.get(target);
const isExistInShallowReadonlyMap = () =>
key === ReactiveFlags.RAW && receiver === shallowReadonlyMap.get(target);
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly;
} else if (
isExistInReactiveMap() ||
isExistInReadonlyMap() ||
isExistInShallowReadonlyMap()
) {
return target;
}
//** 重点二**
const res = Reflect.get(target, key, receiver);
// 问题:为什么是 readonly 的时候不做依赖收集呢
// readonly 的话,是不可以被 set 的, 那不可以被 set 就意味着不会触发 trigger
// 所有就没有收集依赖的必要了
// 只读的数据回改变,也就不需要收集依赖
if (!isReadonly) {
// 在触发 get 的时候进行依赖收集
track(target, "get", key);
}
// shallow只劫持一层
if (shallow) {
return res;
}
if (isObject(res)) {
// 把内部所有的是 object 的值都用 reactive 包裹,变成响应式对象
// 如果说这个 res 值是一个对象的话,那么我们需要把获取到的 res 也转换成 reactive
// res 等于 target[key]
return isReadonly ? readonly(res) : reactive(res);
}
return res;
};
}
function createSetter() {
return function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
// 在触发 set 的时候进行触发依赖
//** 重点三**
trigger(target, "get", key);
return result;
};
}
3、创建Reactive对象的函数
function getTargetType(value: Target) {
return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
? TargetType.INVALID
: targetTypeMap(toRawType(value))
}
function createReactiveObject(target, proxyMap, baseHandlers) {
// 核心就是 proxy
// 目的是可以侦听到用户 get 或者 set 的动作
// 如果命中的话就直接返回就好了
// 使用缓存做的优化点
const existingProxy = proxyMap.get(target);
if (existingProxy) {
return existingProxy;
}
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
const proxy = new Proxy(target, baseHandlers);
// 把创建好的 proxy 给存起来,
proxyMap.set(target, proxy);
return proxy;
}
reactive对对象进行深层代理
核心
- get、set设置:get用公共的createGetter参数isReadonly, shallow没有传,都是undefined;set用公共的createSetter
- 被代理过的数据做缓存reactiveMap
- createReactiveObject创建
// get、set
const mutableHandlers = {
get: createGetter();
set: createSetter(),
};
// 缓存
const reactiveMap = new WeakMap();
function reactive(target) {
createReactiveObject(target, reactiveMap, mutableHandlers);
}
细节
1、公共2部分createGetter函数,重点二部分
- isReadonly没有传,则是undefined,会出发依赖收集
- shallow没有传,则是undefined,不会执行return
- res是对象,需要递归代理
if (!isReadonly) {
track(target, "get", key);
}
if (shallow) {
return res;
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
2、公共2部分createSetter函数,重点三部分
触发依赖
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
// 在触发 set 的时候进行触发依赖
// 重点三
trigger(target, "get", key);
return result;
};
readonly只读代理是深层的,任何被访问的嵌套 property 也是只读的
核心
- get、set设置:get用公共的createGetter参数isReadonly=true,shallow没有传,是undefined;set自定义
- 被代理过的数据做缓存readonlyMap
- createReactiveObject创建
// get、set
const readonlyGet = createGetter(true);
const readonlyHandlers = {
get: readonlyGet,
set(target, key) {
// readonly 的响应式对象不可以修改值
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
);
return true;
},
};
// 缓存
const readonlyMap = new WeakMap();
function readonly(target) {
return createReactiveObject(target, readonlyMap, readonlyHandlers);
}
细节
1、公共2部分createGetter函数,重点二部分
- isReadonly=true,不需要依赖收集,only不允许修改
- shallow没有传,则是undefined,不会执行return
- res是对象的话,需要进行递归代理
if (!isReadonly) {
track(target, "get", key);
}
if (shallow) {
return res;
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
2、set自定义
没有收集依赖,也就不用触发,set时回报错
set(target, key) {
// readonly 的响应式对象不可以修改值
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
);
return true;
},
shallowReactive跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换
核心
- get、set设置:get用公共的createGetter参数isReadonly=fale,shallow=true;set用公共的createSetter
- 被代理过的数据做缓存shallowMap
- createReactiveObject创建
// get、set
const shallowGet = createGetter(false, true);
const shallowHandlers = {
get: shallowGet,
set: createSetter(),
};
// 缓存
const shallowMap = new WeakMap();
function readonly(target) {
return createReactiveObject(target, shallowMap, shallowHandlers);
}
细节
1、公共2部分createGetter函数,重点二部分
- isReadonly=false,需要依赖收集
- shallow=true,执行return res
- 执行不到isObject(res),不进行递归代理
if (!isReadonly) {
track(target, "get", key);
}
if (shallow) {
return res;
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
2、set使用公共的
触发依赖
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
// 在触发 set 的时候进行触发依赖
// 重点三
trigger(target, "get", key);
return result;
};
shallowReadonly使其自身的 property 为只读,但不执行嵌套对象的深度只读转换
核心
- get、set设置:get用公共的createGetter参数isReadonly=true,shallow=true没有true;set自定义
- 被代理过的数据做缓存shallowReadonlyMap
- createReactiveObject创建
// get、set
const shallowReadonlyGet = createGetter(true, true);
shallowReadonlyHandlers = {
get: shallowReadonlyGet,
set(target, key) {
// readonly 的响应式对象不可以修改值
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
);
return true;
},
};
// 缓存
const shallowReadonlyMap = new WeakMap();
function reactive(target) {
createReactiveObject(target, shallowReadonlyMap, mutableHandlers);
}
细节
1、公共2部分createGetter函数,重点二部分
- isReadonly=true,不需要依赖收集
- shallow=true,执行return res
- 执行不到isObject(res),不进行递归代理
if (!isReadonly) {
track(target, "get", key);
}
if (shallow) {
return res;
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res);
}
2、set使用公共的
没有收集依赖,也就不用触发,set时回报错
set(target, key) {
// readonly 的响应式对象不可以修改值
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
);
return true;
},
isReactive、isReadonly、isProxy
- isReactive检查对象是否是由
reactive创建的响应式代理。 - isReadonly检查对象是否是由
readonly创建的只读代理。 - isProxy检查对象是否是由
reactive或readonly创建的 proxy。
核心
公共2部分createGetter函数,重点一部分
// 重点一
const isExistInReactiveMap = () =>
key === ReactiveFlags.RAW && receiver === reactiveMap.get(target);
const isExistInReadonlyMap = () =>
key === ReactiveFlags.RAW && receiver === readonlyMap.get(target);
const isExistInShallowReadonlyMap = () =>
key === ReactiveFlags.RAW && receiver === shallowReadonlyMap.get(target);
if (key === ReactiveFlags.IS_REACTIVE) {
// isReactive的结果
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
// isReadonly的结果
return isReadonly;
} else if (
isExistInReactiveMap() ||
isExistInReadonlyMap() ||
isExistInShallowReadonlyMap()
) {
// isProxy的结果
return target;
}
函数源码
Reactive的get使用的createGetter(),参数isReadonly=undefined
- 代理过:value[ReactiveFlags.IS_REACTIVE] = !undefined = true,return true
- 未代理过:value[ReactiveFlags.IS_REACTIVE] = undefined,return false
export function isReactive(value) {
return !!value[ReactiveFlags.IS_REACTIVE];
}
Readonly的get使用的createGetter(true); 参数isReadonly=true
- 代理过:value[ReactiveFlags.IS_READONLY] = true,return true
- 未代理过:value[ReactiveFlags.IS_READONLY] = undefined,return false
export function isReadonly(value) {
return !!value[ReactiveFlags.IS_READONLY];
}
isProxy源码直接看,不用解释了
export function isProxy(value) {
return isReactive(value) || isReadonly(value);
}
markRaw
标记一个对象,使其永远不会转换为 proxy。返回对象本身。
给对象做一个标记:key=ReactiveFlags.SKIP value=true 描述:可设置、不可枚举
function markRaw(value) {
def(value, ReactiveFlags.SKIP, true)
return value
}
const def = (obj, key, value) => {
Object.defineProperty(obj, key, {
configurable: true,
enumerable: false,
value
})
}
通过公共3部分看到:当target[ReactiveFlags.SKIP]===true或者不可扩展时,直接return target
toRaw
返回 reactive 或 readonly 代理的原始对象。这是一个“逃生舱”,可用于临时读取数据而无需承担代理访问/跟踪的开销,也可用于写入数据而避免触发更改。不建议保留对原始对象的持久引用。请谨慎使用。
toRaw结合公共2部分** 重点一**分析:
- 未代理过直接return value
- 代理过return target(target是代理时用的原对象)
function toRaw(value) {
if (!value[ReactiveFlags.RAW]) {
return value;
}
return value[ReactiveFlags.RAW];
}
const isExistInReactiveMap = () =>
key === ReactiveFlags.RAW && receiver === reactiveMap.get(target);
const isExistInReadonlyMap = () =>
key === ReactiveFlags.RAW && receiver === readonlyMap.get(target);
const isExistInShallowReadonlyMap = () =>
key === ReactiveFlags.RAW && receiver === shallowReadonlyMap.get(target);
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly;
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly;
} else if (
isExistInReactiveMap() ||
isExistInReadonlyMap() ||
isExistInShallowReadonlyMap()
) {
return target;
}