In a similar way to ref,

Difference:

  • Ref is used for basic data types
  • Reactive is used for complex data types
export function reactive(target: Object) {// If this object is a proxy for a readOnly object, then this object is not observable, If (readonlyToraw. has(target)) {return target} // If the original object is readonly, the object is not viewable. Here we use the readonly call, If (readonlyvalues.has (target)) {return readonly(target)} // Call createReactiveObject to create reactive objects Return createReactiveObject(target, // Target rawToReactive, // primitive object mapping WeakMap reactiveToRaw, / / response type mapping of the original Object WeakMap mutableHandlers, / / reactive agent data handler, general is Object and Array mutableCollectionHandlers collection agent handler / / response type, Generally Set, Map, WeakMap, WeakSet)}Copy the code
function createReactiveObject( target: Target, isReadonly: boolean, baseHandlers: ProxyHandler<any>, collectionHandlers: ProxyHandler<any> ) { if (! IsObject (target)) {return target} // Returns target if it is already a proxy object, with the exception of readOnly if it is applied to the response if (target [reactiveFlags.raw] &&! (isReadonly && target[ReactiveFlags.IS_REACTIVE]) ) { return target } const proxyMap = isReadonly ? readonlyMap : Direct const existingProxy = proxymap. get(target) if (existingProxy) {return existingProxy} Const targetType = getTargetType(target) // Only data types in the whitelist can be responded if (targetType === targetType.invalid) {return target} // Hijack the target object with the Proxy API, Make it responsive const proxy = new proxy (target, // Map Set WeakMap WeakSet uses CollectionHandlers Object Array Uses baseHandlers targetType === targetType.COLLECTION? Proxymap.set (target, proxy) return proxy} proxymap.set (target, proxy) return proxy}Copy the code

Whitelist of corresponding data types

function targetTypeMap(rawType: string) {
  switch (rawType) {
    case 'Object':
    case 'Array':
      return TargetType.COMMON // 1
    case 'Map':
    case 'Set':
    case 'WeakMap':
    case 'WeakSet':
      return TargetType.COLLECTION // 2
    default:
      return TargetType.INVALID // 0
  }
}
Copy the code

Conclusion:

Reactive Creates objects

\

  1. If a read-only reactive object is passed in, the reactive object is returned

  2. Otherwise, execute the createReactiveObject method a. Return (with a warning) if it is not an object b. Return (with a warning) if it is already a proxy object, with the exception of readOnly. C. Check whether there is a proxy mapping, take the value from readonlyMap and reactiveMap, and return the value. If there is no proxy mapping, go to D. Check whether the data type is whitelisted. If the data type is not whitelisted, return 0-> non-whitelisted, 1-> Basic data type (including array and object), 2-> set type. E. If so, you can hijack the target object through the Proxy API, make it reactive, and store it in the proxyMap collection

Collection Type Handlers (mutableHandlers)

This method is essentially a hijacking of some operations that access, delete, query, and set the target object

const get = /*#__PURE__*/ createGetter() const set = /*#__PURE__*/ createSetter() export const mutableHandlers: ProxyHandler<object> = {get, // Intercepts read properties of data including target. Syntax and target[] set, // delete property intercepts deleteProperty, // delete has, OwnKeys () {// Access the property name of the object.Copy the code

I’m going to focus on get and set here

function createGetter(isReadonly = false, shallow = false) { return function get(target: Target, key: String | symbol, receiver: object) {/ / evaluated const res = Reflect. Get (target, key, receiver) if (! IsReadonly) {// Rely on collection track(target, trackoptypes.get, key)} // Recursive call response if (isObject(res)) {return isReadonly? readonly(res) : Reactive (res)} function createSetter(shallow = false) {return function set(target: object, key: string | symbol, value: unknown, receiver: object ): boolean { // 1. Const oldValue = (target as any)[key] // 2 Const result = reflect. set(target, key, value, // Don't trigger if target is something up in the prototype chain of original // Issue updates if (target === toRaw(receiver)) { if (! hadKey) { trigger(target, TriggerOpTypes.ADD, key, value) } else if (hasChanged(value, oldValue)) { trigger(target, TriggerOpTypes.SET, key, value, oldValue) } } return result } }Copy the code

Get is evaluated using reflect.get and then determines if it is read-only,

If you don’t call track for dependency collection and then judge the result of evaluation,

If it is an object, call Reactive or Readonly recursively to process the result and return it.

Note:

  • The vue2.0 initialization performs a recursive response to the entire object
  • Vue3.0 only when the initialization of type, the first layer properties accordingly when returns the attributes of the proxy is to visit and is the object and then to the recursive response type, the proxy is hijacked by the object itself, and not to hijack the change of the child object, it is to use this property can delay response type defines the object implementation, at the time of initialization performance will be improved.

Reference: zhuanlan.zhihu.com/p/302380397