What is reactive?

As the data changes, the view is updated

Reactive is also known as the flow of data -> view direction in bi-directional binding.

And just to deepen your understanding of responsiveness. I made a little demo. The initial page value data.name is Bob. When I changed data.name to dani on the console, the page was also updated to dani.

So how does the system know that I changed data.name to dani? The answer is data hijacking

The data was hijacked

Data hijacking is when we write or write data and it is intercepted by a function.

There are actually two ways to implement data hijacking: Object.defineProperty and proxy.

1, the Object. DefineProperty

For data={name: ‘boo’, age: 18}, we can use Object.defineProperty(data, ‘name’, {get() {… }, the set () {… }}) hijack data.name. We call this kind of data that can be hijacked responsive data.

To enable all attributes under data to be hijacked, loop through all keys under data and define property. There is a problem: when I add a gender attribute to data, data.gender = ‘male’. Since data.gender is not defined property, it cannot be hijacked or corresponding.

Because of this JS limitation, defineProperty cannot detect new object properties or array changes!

Vue has also optimized these data:

For the object, data.gender mentioned above, Vue provides a $set method to actively call defineProperty to convert it into responsive data.

This.$set(this. SomeObject, 'b',2) //Copy the code

For arrays, Vue overrides the prototype push, POP, unshift, shift, splice, sort, reverse function hijacking. You might say there are 10 ways to manipulate an array, but you only have 7. Because these are the only seven methods that will change into the array itself. It is also recommended that you use these methods to modify arrays as much as possible during development.

Even with some effort in VUE, arrays that are modified by subscript and length cannot be hijacked.

Vm. items[1] = 'x' // vm.items. Length = 2 // Not responsiveCopy the code

If we have defects, we will optimize it. If we can’t optimize it, we will think about how to reconstruct it. It happens that ES6 provides proxy. Just proxy solves all of the above problems of definePropery. So VUe3 uses proxy for data hijacking.

2, the Proxy
const target = { a: 1, b: 2 } var proxy = new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver); // stop [read] return res; }, set(target, key, value, receiver) { const res = Reflect.set(target, key, value, receiver); // intercept [add, modify] return res; }})Copy the code

As you can see, data reads and writes are intercepted by proxy get and set, respectively.

So why does proxy hijack data?

Of course, our ultimate goal is to update the page.

To update the page, I need to know which functions to update the page rely on reactive data — dependent collection

When the data changes, find the corresponding function that updates the page (the dependency function), execute and update the page — triggering the dependency

So how does vUE do dependency collection and triggering? Let’s find the answer from the source code!!

How does VUE3 implement responsiveness?

How to implement the above demo using the VUe3 API

const { reactive, effect } = VueReactivity; Const data = reactive({name: 'Bob '}); // effect effect. Functions can be collected into dependencies. effect(() => { document.querySelector('#name').innerText = data.name; });Copy the code

Two core functions, Reactive and Effect, are used.

Reactive: Transforms objects into responsive data.

Effect: indicates that the effect of executing the function fn has the side effect that fn may be collected into the dependency collection.

The effect parameter (FN) uses the response data data.name. So the function will be collected into the dependency set corresponding to data.name, and when data.name=’dani’, the dependency function fn will be found to execute and update the page.

So how do reactive and Effect work?

1, the reactive
function reactive(target) { const proxy = new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver); track(target, key); Return isObject(res)? reactive(res) : res; }, set(target, key, value, receiver) { const res = Reflect.set(target, key, value, receiver); trigger(target, key); // Trigger the execution of the corresponding dependent function return res; }}); return proxy; }Copy the code

You can see that track is called in proxy GET for dependency collection. Trigger is called in the set for dependent triggering. How are dependencies collected?

Vue3 defines a targetMaps variable in memory to store dependent functions for all responsive data. The specific data structure is as follows:

Through the above data structure, track(target, key) and trigger(target, key) can easily store and find the corresponding dependency set through target and key.

Review of reactive:

What about the dependency functions collected by track?

The side effect of effect is to collect the function fn into the dependency collection.

2, the effect
function effect(fn) { try { activeEffect = fn; ActiveEffect fn(); } finally {activeEffect = null; }}Copy the code

First, assign fn to the global variable activeEffect, so that FN can be obtained in the subsequent dependency collection.

Then fn is executed. This step is very critical. During fn execution, if any responsive data is read, it will be hijacked by the corresponding proxy get for dependent collection. The dependency collected at this point is activeEffect, which is the function FN being executed.

In other words: if reactive data is used during fn execution, FN will be collected into the dependency set of modified data.

In the figure above you can see that Effect performs FN, a complete dependency collection process. When data changes, it will be hijacked by the proxy’s SET, triggering the execution of the corresponding dependency function.

3, process,

This is the reactive principle of VUe3 ~~~~