这篇文章主要讲解了“vue3中reactive和ref的区别是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue3中reactive和ref的区别是什么”吧!
成都创新互联公司成立于2013年,先为浑源等服务建站,浑源等地企业,进行企业商务咨询服务。为浑源企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
reactive
源码地址:packages/reactivity/reactive.ts
首先我们看一下vue3
中用来标记目标对象target
类型的ReactiveFlags
// 标记目标对象 target 类型的 ReactiveFlags
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 // target 是否是响应式
[ReactiveFlags.IS_READONLY]?: boolean // target 是否是只读
[ReactiveFlags.RAW]?: any // 表示proxy 对应的源数据, target 已经是 proxy 对象时会有该属性
}
reactive
export function reactive(target: T): UnwrapNestedRefs
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
// 如果目标对象是一个只读的响应数据,则直接返回目标对象
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
return target
}
// 创建 observe
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
reactive
函数接收一个target
对象,如果target
对象只读则直接返回该对象
若非只读则直接通过createReactiveObject
创建observe
对象
createReactiveObject
看着长不要怕,先贴createReactiveObject
完整代码,我们分段阅读
/**
*
* @param target 目标对象
* @param isReadonly 是否只读
* @param baseHandlers 基本类型的 handlers
* @param collectionHandlers 主要针对(set、map、weakSet、weakMap)的 handlers
* @param proxyMap WeakMap数据结构
* @returns
*/
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler,
collectionHandlers: ProxyHandler,
proxyMap: WeakMap
) {
// typeof 不是 object 类型的,在开发模式抛出警告,生产环境直接返回目标对象
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// target is already a Proxy, return it.
// exception: calling readonly() on a reactive object
// 已经是响应式的就直接返回(取ReactiveFlags.RAW 属性会返回true,因为进行reactive的过程中会用weakMap进行保存,
// 通过target能判断出是否有ReactiveFlags.RAW属性)
// 例外:对reactive对象进行readonly()
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// target already has corresponding Proxy
// 对已经Proxy的,则直接从WeakMap数据结构中取出这个Proxy对象
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// only a whitelist of value types can be observed.
// 只对targetTypeMap类型白名单中的类型进行响应式处理
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
// proxy 代理 target
// (set、map、weakSet、weakMap) collectionHandlers
// (Object、Array) baseHandlers
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
}
首先我们看到createReactiveObject
接收了五个参数
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler,
collectionHandlers: ProxyHandler,
proxyMap: WeakMap
target 目标对象
isReadonly 是否只读
baseHandlers 基本类型的 handlers处理数组,对象
collectionHandlers处理 set、map、weakSet、weakMap
proxyMapWeakMap数据结构存储副作用函数
这里主要是通过ReactiveFlags.RAW
和ReactiveFlags.IS_REACTIVE
判断是否是响应式数据,若是则直接返回该对象
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
对于已经是Proxy
的,则直接从WeakMap
数据结构中取出这个Proxy对象并返回
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
这里则是校验了一下当前target
的类型是不是Object
、Array
、Map
、Set
、WeakMap
、WeakSet
,如果都不是则直接返回该对象,不做响应式处理
// 只对targetTypeMap类型白名单中的类型进行响应式处理
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
校验类型的逻辑
function getTargetType(value: Target) {
return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
? TargetType.INVALID
: targetTypeMap(toRawType(value))
}
function targetTypeMap(rawType: string) {
switch (rawType) {
case 'Object':
case 'Array':
return TargetType.COMMON
case 'Map':
case 'Set':
case 'WeakMap':
case 'WeakSet':
return TargetType.COLLECTION
default:
return TargetType.INVALID
}
}
所有的前置校验完后,就可以使用proxy
代理target
对象了
这里使用了一个三目运算符
通过TargetType.COLLECTION
来执行不同的处理逻辑
// proxy 代理 target
// (set、map、weakSet、weakMap) collectionHandlers
// (Object、Array) baseHandlers
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
现在对createReactiveObject
的执行逻辑是不是就很清晰了
到这里还没有结束,createReactiveObject
中最后proxy
是如何去代理target
的呢?这里我们用baseHandlers
举例,深入baseHandlers
的内部去看看
baseHandlers
源码地址:packages/reactivity/baseHandlers.ts
在reactive.ts
中我们可以看到一共引入了四种 handler
import {
mutableHandlers,
readonlyHandlers,
shallowReactiveHandlers,
shallowReadonlyHandlers
} from './baseHandlers'
我们以mutableHandlers
为例
// 可变处理
// const get = /*#__PURE__*/ createGetter()
// const set = /*#__PURE__*/ createSetter()
// get、has、ownKeys 会触发依赖收集 track()
// set、deleteProperty 会触发更新 trigger()
export const mutableHandlers: ProxyHandler