reactive API
Function reactive (target) {// Already a readonly 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>) {// Must be object or array type, return target if (! IsObject (target)) {return target} if (target [reactiveFlags.raw] &&! (isReadonly && target[reactiveFlags.is_Reactive]) {return target} // Check whether readonlyMap and reactiveMap exist. Reactive and Readonly (reactive and Readonly) const proxyMap = isReadonly? readonlyMap : ReactiveMap const existingProxy = proxymap. get(target) if (existingProxy) {return existingProxy TargetType = getTargetType(target) if (targetType === targetType.invalid) {return target} Const proxy = new proxy (target, targetType === targetType.collection? Proxymap. set(target, proxy) return proxy}Copy the code
Reactive Creation Process
- Already a Readonly proxy, return this proxy directly
- Must be an object or array type, otherwise return Target
- Target is already a Proxy object and returns Proxy directly.
- Check whether readonlyMap and reactiveMap exist. Return the proxy directly
- Must be the specified data type, otherwise return Target. Object and Array are 1, Map, Set, WeakMap and WeakSet are 2. Remove RegExp and Date
- The configuration varies according to the data type. Finally, put it into the corresponding 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, etc. ReadonlyHandlers const proxy = new proxy (target, targetType === targetType.collection? collectionHandlers : baseHandlers ) ... }Copy the code
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
}
}
Copy the code
Here you can see that the set and delete operations return true directly. A warning is also reported without modifying properties.
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 } }Copy the code
- Readonly does not rely on collection and cannot be modified
- If property has object, array, depth traversal all changed to read-only
ref API
The Reactive API limits the type of target passed in, which must be Object or Array. Basic types (such as String, Number, Boolean) are not supported
It’s too cumbersome to encapsulate an object to make an underlying data type reactive. So you have the REF API
const a = ref({value:1})
const b = shallowRef({})
a.value = '1111'
Copy the code
export function ref(value? : unknown) {return createRef(value)} function isRef(r: any): r is Ref { return Boolean(r && r.__v_isRef === true) } function createRef(rawValue: Shallow = false) {// shallow = false RawValue if (isRef(rawValue)) {return rawValue} return new RefImpl(rawValue, Shallow)} class RefImpl<T> {shallow)} class RefImpl<T> Public readonly __v_isRef = true constructor(private _rawValue: constructor) T, public readonly _shallow = false) {reactive object this._value = _shallow? _rawValue : isObject(val) ? reactive(val) : // When accessing the value attribute, Get value() {track(toRaw(this), trackoptypes.get, 'value') return this._value} Trigger the trigger function to send out notifications, _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) } } }Copy the code
- Ref returns an Object
- If rawValue is already a ref, return rawValue
- If rawValue is an Object, operate rawValue reactive
- Use shallowRef and do not operate rawValue reactive
Elaborate said ref
Ref is different from Reactive. Reactive returns a proxy, ref returns an object const a = ref(1); {// flag isRef __v_isRef: true // private to store the passed argument _rawValue: 1 _shallow: false // private to store the passed argument _value: __proto__: {value: 1}}Copy the code
Difference between _rawValue and _value
_rawValue saves the passed argument _value if an object is passed and ref is used instead of shallowRef. _value stores the reactive ProxyCopy the code
__v_isRef
const a = ref({ __v_isRef: true, a: 1 }); If you create a ref like this, it will return the target without doing anything.Copy the code
reactive | readonly | ref | |
---|---|---|---|
parameter | Object, Array, Map, Set, WeakMap, WeakSet | Object, Array, Map, Set, WeakMap, WeakSet | Any value |
read-only | Can be modified | read-only | Can be modified |
The return value | Proxy | Proxy | Object |
Reactive can only use Object, Array, Map, Set, WeakMap, WeakSet, while REF can use any value and can also be reactive if the parameter is Object