[Vue3 source code analysis] computed

export function computed<T>(
  getter: ComputedGetter<T>,
  debugOptions?: DebuggerOptions
): ComputedRef<T>
export function computed<T>(
  options: WritableComputedOptions<T>,
  debugOptions?: DebuggerOptions
): WritableComputedRef<T>
export function computed<T>(
  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
  debugOptions?: DebuggerOptions,
  isSSR = false
) {<!-- -->
  //Formatting parameters
  let getter: ComputedGetter<T>
  let setter: ComputedSetter<T>

  // If what is passed is a function (that is, functional writing), then it is read-only.
  const onlyGetter = isFunction(getterOrOptions)
  if (onlyGetter) {<!-- -->
    getter = getterOrOptions // The function we passed is assigned to the getter
    setter = __DEV__ // Setter is not supported, otherwise an error will be reported
      ? () => {<!-- -->
          console.warn('Write operation failed: computed value is readonly')
        }
      :NOOP
  } else {<!-- --> //Optional writing method, readable and writable
    getter = getterOrOptions.get
    setter = getterOrOptions.set
  }

  // Pass getters and setters into this class
  const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)

  if (__DEV__ & amp; & amp; debugOptions & amp; & amp; !isSSR) {<!-- -->
    cRef.effect.onTrack = debugOptions.onTrack
    cRef.effect.onTrigger = debugOptions.onTrigger
  }

  return cRef as any
}

This code is the logic inside the computed function, which is used to create the getter and setter< of the computed property based on the passed parameter getterOrOptions /code>, then create an instance of ComputedRefImpl and return it.

Here is a detailed explanation of the code:

  1. First, the getter and setter variables are defined for subsequent storage of the getter and setter functions of the computed properties.

  2. Determine whether it is written in functional style or option style by checking whether getterOrOptions is a function. Functional writing means that the computed property is read-only, so getterOrOptions is assigned directly to the getter variable, and the setter variable is set to a function. This function is used to report an error in the development environment, prompting the user that the read-only computed property cannot be written.

    // Read-only calculated properties, directly use the incoming getter function
    if (onlyGetter) {<!-- -->
      getter = getterOrOptions; // The function passed in is used as a getter
      setter = __DEV__ // If it is a development environment, set the setter as a warning function
        ? () => {<!-- -->
            console.warn('Write operation failed: computed value is readonly')
          }
        : NOOP; // Otherwise set to empty function NOOP
    }
    
  3. If it is not written in a functional way, it means that the calculated attribute is readable and writable. At this time, the get and set functions are extracted from the incoming getterOrOptions object and assigned to getter and setter variable.

    } else {<!-- --> // Option writing, can read and write
      getter = getterOrOptions.get; // Extract getter from options object
      setter = getterOrOptions.set; // Extract setter from options object
    }
    
  4. Create a ComputedRefImpl instance cRef and set the getter, setter, read-only flag, and isSSR Parameters are passed in. cRef represents the final computed property object.

    //Create ComputedRefImpl instance
    const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
    
  5. In the development environment, if the debugging option debugOptions is passed in and it is not server-side rendering (isSSR is false), the debugging options will be The onTrack and onTrigger callback functions are assigned to cRef.effect.onTrack and cRef.effect.onTrigger respectively, for Track dependencies and triggering of computed properties.

    if (__DEV__ & amp; & amp; debugOptions & amp; & amp; !isSSR) {<!-- -->
      cRef.effect.onTrack = debugOptions.onTrack;
      cRef.effect.onTrigger = debugOptions.onTrigger;
    }
    
  6. Finally, the created cRef object is returned, which contains information such as the value of the calculated property, get and set functions, etc.

    return cRef as any;
    

In short, this code is the logic inside the computed function, which is used to create the getter and setter functions of the calculated property based on the parameters passed in, and Finally, a ComputedRefImpl instance is created and the computed property object is returned. Depending on the writing method and configuration, you can create read-only or read-writable computed properties.

Then let’s look specifically at the ComputedRefImpl instance:

export class ComputedRefImpl<T> {<!-- -->
  public dep?: Dep = undefined

  private_value!: T
  public readonly effect: ReactiveEffect<T>

  public readonly __v_isRef = true
  public readonly [ReactiveFlags.IS_READONLY]: boolean = false

  public _dirty = true // Check if it is dirty and needs to be recalculated
  public_cacheable: boolean

  constructor(
    getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean,
    isSSR: boolean
  ) {<!-- -->
    //Create a ReactiveEffect object to manage responsive dependencies of computed properties
    // If the dependency changes and the dirty value is false, this function will only be executed if the dependency changes
    this.effect = new ReactiveEffect(getter, () => {<!-- -->
      if (!this._dirty) {<!-- -->
        this._dirty = true
        triggerRefValue(this)
      }
    })

    //Associate the computed property with the ReactiveEffect object
    this.effect.computed = this
    this.effect.active = this._cacheable = !isSSR // Set whether to cache the calculation results based on whether to render on the server side
    this[ReactiveFlags.IS_READONLY] = isReadonly // Whether the tag is a read-only computed property
  }

  // When the dirty value is received as true, directly execute the get value function
  get value() {<!-- -->
    // Obtain method of calculated properties, used to obtain the value of calculated properties
    const self = toRaw(this) // Get the original computed property object and break away from the Proxy proxy
    trackRefValue(self) // Track the reference of the calculated property
    if (self._dirty || !self._cacheable) {<!-- -->
      // Recalculate the attribute value if the attribute is marked dirty (requires recalculation) or is not cacheable
      self._dirty = false
      self._value = self.effect.run()! // Run the computed property's effect function to calculate the new value
    }
    return self._value
  }

  set value(newValue: T) {<!-- -->
    // Setting method of calculated properties, used to set the value of calculated properties
    this._setter(newValue) // Call the user-provided setter function
  }
}

This code defines the ComputedRefImpl class, which is part of the implementation of computed properties (computed) in Vue 3.

The main explanation of the code is as follows:

  1. The ComputedRefImpl class is used to implement computed properties. It accepts the following parameters:

    • getter: The getter function of the calculated attribute, used to calculate the value of the attribute.
    • _setter: The setting function of the calculated property, used to set the value of the calculated property.
    • isReadonly: A Boolean value indicating whether the computed property is read-only.
    • isSSR: A Boolean value indicating whether to render on the server side.
  2. In the constructor, a ReactiveEffect object is created, the getter function is passed to it, and a callback function is defined. This callback function will be triggered when the dependency of the computed property changes. The callback function will set the _dirty attribute to true, indicating that the calculated attribute needs to be recalculated, and call triggerRefValue(this) to notify relevant dependencies to update .

  3. Associate the created ReactiveEffect object with the current ComputedRefImpl instance for subsequent management and tracking.

  4. Set the active attribute and _cacheable attribute of effect based on the parameters passed in. active indicates whether the calculation needs to be stopped when the calculated attribute is deactivated, and _cacheable indicates whether the calculation results can be cached.

  5. Define the get value() method to get the value of a computed property. Before getting the property value, trackRefValue(self) is called to track the reference of the calculated property. If a computed property is marked dirty (requires recalculation) or is not cacheable, the property value will be recalculated and _dirty will be set to false to indicate that the property value has been calculated. .

  6. Define the set value(newValue: T) method, which is used to set the value of the calculated property. It will call the user-provided _setter function to set the attribute value.

In short, this code implements the core logic of calculated attributes, including obtaining and setting attribute values, as well as calculating and cache management of attribute values. Computed properties can be automatically updated based on their dependencies, and can optionally be made read-only.

syntaxbug.com © 2021 All Rights Reserved.