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

  1. Already a Readonly proxy, return this proxy directly
  2. Must be an object or array type, otherwise return Target
  3. Target is already a Proxy object and returns Proxy directly.
  4. Check whether readonlyMap and reactiveMap exist. Return the proxy directly
  5. 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
  6. 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
  1. Readonly does not rely on collection and cannot be modified
  2. 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
  1. Ref returns an Object
  2. If rawValue is already a ref, return rawValue
  3. If rawValue is an Object, operate rawValue reactive
  4. 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