Vue3.0给我们提供的这两个方法,toRaw方法是把被reactive或readonly后的Proxy对象转换为原来的target对象,而markRaw则直接让target不能被reactive或readonly。
先看看toRaw怎么用,
setup(){
let obj = {
msg: 'hello',
student: {
name: 'xiaoliu',
age: 20
}
}
let reactiveObj = reactive(obj)
let state = toRaw(reactiveObj)
return {state}
}
用法很简单,看看转换前后Proxy对象和target对象:
上图是进行reactive后的Proxy对象,看看对其toRaw后,
toRaw后,Proxy对象又被转换回去了。还记得在调用createReactiveObject进行Proxy时,用WeakMap数据结构把target和Proxy对象联系起来了:proxyMap.set(target, proxy)。
toRaw就通过Proxy把target给提取出来,看看具体怎么做的:
export function toRaw<T>(observed: T): T {
return (
(observed && toRaw((observed as Target)[ReactiveFlags.RAW])) || observed
)
}
function createGetter(isReadonly = false, shallow = false) {
return function get(target: Target, key: string | symbol, receiver: object) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly
} else if (
key === ReactiveFlags.RAW &&
receiver === (isReadonly ? readonlyMap : reactiveMap).get(target)
) {
//在这里把通过比较Proxy,把target给找出来
return target
}
如果传给toRaw的参数不是Proxy对象则原样返回。
接下来看看markRaw方法,
export function markRaw<T extends object>(value: T): T {
//给target增加一个ReactiveFlags.SKIP属性
def(value, ReactiveFlags.SKIP, true)
return value
}
export const def = (obj: object, key: string | symbol, value: any) => {
Object.defineProperty(obj, key, {
configurable: true,
enumerable: false,
value
})
}
function getTargetType(value: Target) {
//判断如果target有ReactiveFlags.SKIP属性,则直接判断不在可以进行reactive的白名单中,从而不能进行reactive
return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
? TargetType.INVALID
: targetTypeMap(toRawType(value))
}
markRaw通过增加一个属性标志ReactiveFlags.SKIP,来判断是否能进行reactive,非常简单,不再进行表述了。
toRaw在实际的业务开发中感觉用的频次应该比较低。