preface

Today this article is for all the response in the vue3 parsing API do a principle, some of which have been in front of a few article explains, reactive, shallowReactive, readonly, shallowReadonly in Vue3.2 reactive principle of parsing (2), Ref is analyzed in # Vue3.2, and the rest of the API is analyzed in this article.

Calculate attribute

Computed can accept a getter to return an unwritable ref

const count = ref(0)
const double = computed(() = > {
    return count.value * 2
})
double.value = 4 / / warning
Copy the code

You can also accept a configuration object that has a setter and getter inside it and returns a ref that can be written to

const count = ref(1)
const plusOne = computed({
  get: () = > count.value + 1.set: val= > {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) / / 0
Copy the code

But generally use most is its getter, computed the source location in vue – next/packages/reactivity/SRC/computed. The ts, implement specific as follows:

Declare two variables to store the methods passed in by the user. The onlyGetter result is to determine if the user has just passed in a getter function. Based on that result, the variable is copied, but some users have passed in a configuration object that only has the getter function in it. If the value of a setter variable is passed in reverse, false means it is not read-only, otherwise it is read-only.

Let’s start with a few attributes:

Dep: Very common, is a side effect function that depends on this data,

_value: Calculates the cached value for each change of the attribute. If the value is the same as this value, it indicates that the attribute has not changed

_dirty: Prevents multiple triggers, in the case of chain calls

Effect: Side effects of this calculated property

__v_isRef: This is a ref, and a computable ref

The final marker is whether the computed property can be changed

The constructor

The main purpose of the constructor is to have a side effect on this computed property, the getter is passed in by the user, and the scheduler is usually called in triggerEffects to modify the responsive data that the computed property depends on, and the scheduler does if to prevent computed property from being computed by chain, Subsequent microtasks perform the triggerRefValue multiple times, that is, one change, until all processing is complete before the next change

Get and update

In terms of value acquisition and update, it is similar to ref in that it uses access descriptors. The difference is that REF can get and return values directly from itself. For computed, it requires the getter method passed in by the user to get the latest data, or returns the cached value if the cached value is the latest. For computed data, users need to pass setter methods (if the ref is writable, if the ref is not writable, it is read-only) to update the value. Otherwise, a warning will be given.

In the get method, did some processing, calculating the value of the property agent might be something else, must pass toRaw () to get the value of the original, normal collection depend on the following if judgment is to prevent the chain in the call, when get the value, is to execute the getter method, if the value is unchanged, the cache is the latest, Just return the cache

Other supplementary

After executing the core logic, give a debug in development modecomputedThe chance that the end will be calculablerefreturn

Possible delay calculation property API

In VUe3.2, a new responsive APIdeferredComputed has been updated, but the API is not available yet, but we can take a quick look at its implementation to see how it differs from computed. Specific implementation in: vue – next/packages/reactivity/SRC/deferredComputed ts,

The entry point is very simple, and as you can see, the core logic is thereDeferredComputedRefImplIn, and can only be passedgetterMethod, it seems that the delayed calculation of the data is not able to modify, the following look at the core logic

So let’s look at attributes, which are actually similar to computed, so if I skip this,

Compared with computed direct computing, deferredComputed does not execute immediately after it triggers its scheduling function, but instead queues it up for someone to execute it at some point in the future (when its dependent execution is complete, it calls the scheduling function in the queue). And to prevent multiple executions of its own triggerRefValue, a validation is performed so that the latest value is the same as the cached value.

The rest of the way to get values is exactly the same as computed. I personally think that this API might be used for computations that rely on asynchronous data and have to be delayed. In VUe3.0, the code for the two apis actually goes together. Maybe it was to separate the two, to separate them.

Monitoring properties

There are many apis for vue3 to monitor data, such as the common Watch, as well as vue2’s Watch configuration, watchEffect, effect and this.$watch. WatchEffect also has two derivatives, APIwatchPostEffect and watchSyncEffect. If we look at their respective implementations, we can find that they actually call the same method doWatch, which achieves different effects according to the different arguments passed. Ue-next/Packages/Runtime-core/SRC/apiwatch.ts

DoWatch (source as any, cb, options), watchEffect () Return doWatch(effect, null, options). It’s a big function, so let’s look at it piecewise

DoWatch accepts three parameters: source: monitor data, CD: execute side effects function after data changes, options: monitor configuration options of data, including immediate: execute immediately, deep: monitor, and flush: Whether to execute asynchronously or synchronously, onTrack and onTrigger are used for debugging during the development process.

Instance the getter of the current instance will retrieve the data when the data changes. ForceTrigger: the data must be updated after the data changes. IsMultiSource: there are multiple data sources.

To get the data

The first part is to process the getter method of obtaining data, mainly relying on source for processing, and whether the key point is function or not. Watch supports the writing method of () => data, and can also directly write the data name. If it is the data name, no further processing is needed.

If it is a function that needs further judgment and watchEffect is also a function, then it is necessary to judge the second parameter of doWatch. The second parameter passed by Watch and watchEffect call to doWatch is one function and the other is null. In another case, an array is passed in, which means multiple data needs to be monitored.

The last else is passed with nothing, defaults to a NOOP to prevent errors, and may be replaced with another function at some point in the future.

Other processing

The second part is some processing, such as: VUe2 array watch compatibility, deep monitoring processing, providing a function to the user to cancel the side effect of the pending asynchronous function (asynchronous request). There is also server-side rendering.

Traverse is called when deep monitoring is performed. The traverse function is used to find data faster and monitor changes in data. The “SEEN” variable is cached in “Seen” for the first time, and cached in “SEEN” for changes. This improves performance by reducing the need to search for data every time.

Asynchronous scheduling function

We’ve already produced a getter, which is executed as soon as the data changes, but sometimes we don’t need to execute it immediately. Instead, we queue it up and wait for it to finish rendering. The main logic of the job function is to execute the cb function passed by the user. During the process, the cancellation function of the user registration will not be executed at the first time, but will be executed from the second time, and then wrapped into a scheduling function.

Vue2 has only one scheduling function. Sync: perform synchronization directly. Post: put the component into the render queue and wait for the completion of rendering before executing it. This is where the two watchEffect derivatives come from.

Finally, the function of uninstalling monitoring is returned, and the analysis of doWatch function is finished.

The realization of this $watch

This is a dummy parameter. The remaining three parameters are: source monitoring data source, value: may be a function, if not configuration object, options: configuration object.

Getters can be handled in three ways: 1. The name of the data directly; 2. Function () => XXX 3. If it is xxx.ccC. aaa, it is probably an object, and createPathGetter is used to handle this.

CTX is the instance proxy object of the current component. Path is usually passed as aaA.bbb. CCC, and its data structure is {aaa: {BBB: {CCC: 10}}}, which returns a method that can loop in and fetch data from the proxy object.

{handler: () => {}, deep: {handler: () => {}, deep: Handler to cb and then value to options.

I set this(instance of calling $watch) to currentInstance, but after calling doWatch, I set currentInstance back. At first, I was confused about this operation. This will be used again until Lenovo implements doWatch, but this is used so as not to break the previous one.

The Effect scope

Effect scope is a high-level API that primarily serves library authors. Consult the appropriate RFC for details on its use. In the development of business, we are not commonly used, basically is to serve users based on VUE secondary development. Let’s just do a simple analysis. Source address: vue – next/packages/reactivity/SRC/effectScope ts

effectScopen

Creates an effect scoped object to capture reactive effects (such as compute properties or listeners) created within it so that they can be processed together.

recordEffectScope

Specifies an EffectScopen for an effect. if this is not specified, the default is the currently active EffectScope.

getCurrentScope

Returns the current active scope, if any

onScopeDispose

Registers a processing callback on the currently active effect scope. This callback is invoked after the relevant effect scope ends. This method can be used as a non-component coupling alternative to onUmounted when reusing composite functions, because the setup() function of each Vue component is also called in the effect scope.

EffectScope

The activeEffectScope and EffectScope are used to create a new Effect scope. The activeEffectScope and EffectScope are used to create a new Effect scope. ActiveEffectScope is just a global variable, easy to use everywhere, mainly to see the implementation of EffectScope.

attribute

effects: the currentEffectThe scope ofeffect.

Cleanups: all functions executed when all effects in the current Effect scope are stopped,

Parent: the parent Effect scope of the current Effect scope,

Scopens: Stores all child Effect scopes of the current Effect scope.

Index: index of the current Effect scope in the parent current Effect scope

The constructor

If is instantiated by creating an instance method Not to enter the if Because the side effects of each component scope is independent cannot interfere with each other, but if it is instantiated in a component instance The side effects of the current component instance scope will be as a new produce the side effects of the scope of the parent scope (storage) on the parent attribute, There will also be a variable in the parent scope that stores all the scopes that belong to it, and the index variable will be marked in the child scope.

Members of the method

The rest of the methods operate on all effects in the generated Effect scope. For example, to execute all effects, you can call on method, and to stop all effects, you can call off method.

Additional points: Difference between Effect and watchEffect

Both Effect and watchEffect can pass a side effect function, and both can trace the function inside the side effect. However, after testing, it is found that if the function passed by watchEffect contains if and other conditional statements, the data in the function whose condition judgment is not valid will not be tracked. This is called update dependency tracking. On the other hand, effect is tracked regardless of the condition.

The above is my analysis of the implementation principle of the responsive API of VUe3.2. If there is something wrong or missing, please point it out. If you have a better understanding, I hope you can explain it in the comments section, thank you.