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:
-
First, the
getter
andsetter
variables are defined for subsequent storage of the getter and setter functions of the computed properties. -
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, sogetterOrOptions
is assigned directly to thegetter
variable, and thesetter
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 }
-
If it is not written in a functional way, it means that the calculated attribute is readable and writable. At this time, the
get
andset
functions are extracted from the incominggetterOrOptions
object and assigned togetter
andsetter
variable.} else {<!-- --> // Option writing, can read and write getter = getterOrOptions.get; // Extract getter from options object setter = getterOrOptions.set; // Extract setter from options object }
-
Create a
ComputedRefImpl
instancecRef
and set thegetter
,setter
, read-only flag, andisSSR
Parameters are passed in.cRef
represents the final computed property object.//Create ComputedRefImpl instance const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
-
In the development environment, if the debugging option
debugOptions
is passed in and it is not server-side rendering (isSSR
isfalse
), the debugging options will be TheonTrack
andonTrigger
callback functions are assigned tocRef.effect.onTrack
andcRef.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; }
-
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:
-
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.
-
In the constructor, a
ReactiveEffect
object is created, thegetter
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 totrue
, indicating that the calculated attribute needs to be recalculated, and calltriggerRefValue(this)
to notify relevant dependencies to update . -
Associate the created
ReactiveEffect
object with the currentComputedRefImpl
instance for subsequent management and tracking. -
Set the
active
attribute and_cacheable
attribute ofeffect
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. -
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 tofalse
to indicate that the property value has been calculated. . -
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.