We introduced the principle of responsivity in the previous chapter. In this article, we will explore the implementation principle of computational properties in Vue 3.0. If you have not read the previous article, please read the previous article before reading this article, otherwise it may be a little confused.

Method of use

Let’s first look at the use of computed attributes:

Code description:

ComputedCounter is defined using the computedAPI, which has a get method that returns the square of the reactive data counter, and a set method that sets the value of counter.

As the value of counter changes, the value of the computedCounter changes.

Implementation logic

computed API

Let’s start by looking at how computed handles passed parameters:

Code explanation:

  1. computedAccepts two forms of passing parameters. The first is passing only one function (e.g.computed(() => counter.value * counter.value)), the second is to pass in an includegetandsetThe object of two functions;
  2. The first type of pass assigns the function togetterThe second method is to communicate to the participantsgetandsetTwo functions are assigned togetterandsetterMethods;
  3. willgetterandsetterMethods usingComputedRefImplEncapsulate;
  4. returnComputedRefImplThis object.

ComputedRefImpl

Next let’s look at the implementation inside ComputedRefImpl:

Code explanation:

  1. Constructor directly passed insetterAssigned to_setter, the use ofReactiveEffectwillgetterEncapsulate, and then assign the encapsulated result toeffect.
  2. Get and set functions are provided.

ComputedRefImpl##get

The get function must be called when the corresponding value is obtained.

{{computedCounter}}

  1. The dependencies are collected when the get function is called, and the component rendering function is collectedcomponentUpdateFn;
  2. The first time I do it_dirtyfortrue, so it will be executedeffect.run(). The logic of this function is as follows:
    • First theeffectPush theeffectStackStack, and willactiveEffectPoint to theeffect;
    • performgetterMethods thecounter.value * counter.value;
    • When callingcounter.valueTriggered whencounterthegetThe function,counterThe dependencies are then collected, and the collected dependencies areeffectFunction.

  3. I get a new value.

ComputedRefImpl##setModify the logic of reactive data triggering

set value(newValue: T) {
    this._setter(newValue)
}
Copy the code

Dependencies are distributed when the value of counter is changed, since counter has two dependencies:

  • computedCountertheeffectFunction:
if (! this._dirty) { this._dirty = true triggerRefValue(this) }Copy the code

The logic is to set _dirty to true, and then trigger the dependency, which is the component’s side effect rendering function.

Note: This _dirty setting to true is key.

  • Component side effects render functions:

Component side effects The rendering function triggers a re-rendering of the component and then calls the GET function when the computedCounter value is obtained, with _dirty set to true, and the new value recalculated by calling effect.run() as in the first rendering.

if (self._dirty) {
    self._dirty = false
    elf._value = self.effect.run()!
}
Copy the code

At this point, as with the first rendering, we enter a new round of dependency collection. Over and over again, until the program ends.

conclusion

  • If the dependent data is unchanged, the calculation attribute will not be recalculated and the cached value will be directly used. Although this performance improvement is not obvious, this kind of optimization thinking is always needed.

  • In addition, if the calculated attribute is not obtained, the corresponding value will not be computed, which has the characteristics of delayed acquisition.