Is vue2's responsive principle "obsolete"? Continue to observe vue3 the principle of responsive Proxy

Posted by rsanc on Sat, 29 Jan 2022 03:32:44 +0100

I wrote an article about vue2 X's responsive principle, but because vue3 also came and followed the pace of vue3, I began to learn the responsive principle of vue3 on Monday.

You should have heard that vue3 uses proxy to solve the responsive principle, and it solves the object in vue2 Definepropery has some problems, but it also brings some problems.

In the following article, we will explain how vue3 uses proxy to implement responsive expressions and some problems brought about by it. Let's study together 💯

I 🟩 Review object defineProperty

Here, you need to have a prior understanding of the knowledge points of ObjectProperty, If you need to know, you can click the article to view it~

Now, let's review object Disadvantages of defineproperty:

  • One time recursion is required for deep monitoring;
  • Unable to listen for new attributes / delete attributes (need to be used with Vue.set or Vue.delete);
  • Cannot listen to the array natively. Special processing is required.

With object For these shortcomings of defineproperty, next we begin to enter the world of Proxy.

II 🟨 Proxy basic usage

Here is a code to demonstrate the basic use of Proxy. The specific codes are as follows:

const data = {
	name: 'monday',
    age:18
}
//const data = ['a', 'b', 'c']

const proxyData = new Proxy(data, {
    get(target, key, receiver){
        //Handle only its own (non prototype) properties
        const ownKeys = Reflect.ownKeys(target)
        if(oenKeys.includes(key)){
            console.log('get', key) //monitor
        }
        const result = Reflect.get(target, key, receiver)
        return result // Return results
    },
    set(target, key, val, receiver){
        //Duplicate data, not processed
        if(val === target[key]){
            return true
        }
        
        const result = Reflect.set(target, key, val, receiver)
        console.log('set', key, val)
        //console.log('result', result) //true
        return result // Set successfully
    },
    deleteProperty(target, key){
        const result = Reflect.deleteProperty(target, key)
        console.log('delete property', key)
        return result // Delete successfully
    }
})

From the above code, we first define the literal data of an object, and then pass it as the parameter of Proxy instantiation. And proxyData implements the methods of get, set and deleteProperty, which can add, delete and modify data.

III 🟦 Learn Proxy syntax: Reflect

Let's meet a good friend of Proxy, Reflect.

The Reflect object has the ability of one-to-one correspondence with the proxy. The Reflect object has a total of 13 static methods, which means that the proxy we usually hear has up to 13 interception behaviors, and the 13 static methods of Reflect match the 13 interception behaviors of the proxy.

Static method list
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.has(obj, name)
Reflect.deleteProperty(obj, name)
Reflect.construct(target, args)
Reflect.getPrototypeOf(obj)
Reflect.setPrototypeOf(obj, newProto)
Reflect.apply(func, thisArg, args)
Reflect.defineProperty(target, propertyKey, attribute)
Reflect.getOwnPropertyDescriptor(target, propertyKey)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.ownKeys(target)

Reflect appears to replace the tool functions on the Object. It will not be introduced in detail here, See the document for details .

IV 🟧 How Vue3 uses Proxy to implement responsive

1. Achieve responsive

Let's implement the response of Proxy. Attach Code:

// Create responsive
function reactive(target = {}) {
    if (typeof target !== 'object' || target == null) {
        // Not an object or array, returns
        return target
    }

    // Agent configuration
    const proxyConf = {
        get(target, key, receiver) {
            // Handle only its own (non prototype) properties
            const ownKeys = Reflect.ownKeys(target)
            if (ownKeys.includes(key)) {
                console.log('get', key) // monitor
            }
    
            const result = Reflect.get(target, key, receiver)
        
            // Depth monitoring
            return reactive(result)
        },
        set(target, key, val, receiver) {
            // Duplicate data, not processed
            if (val === target[key]) {
                return true
            }
    
            const ownKeys = Reflect.ownKeys(target)
            // Judge whether the attribute is an existing attribute or a new attribute
            if (ownKeys.includes(key)) {
                console.log('Existing key', key)
            } else {
                console.log('New key', key)
            } 

            const result = Reflect.set(target, key, val, receiver)
            console.log('set', key, val)
            // console.log('result', result) // true
            return result // Set successfully
        },
        deleteProperty(target, key) {
            const result = Reflect.deleteProperty(target, key)
            console.log('delete property', key)
            // console.log('result', result) // true
            return result // Delete successfully
        }
    }

    // Generate proxy object
    const observed = new Proxy(target, proxyConf)
    return observed
}

// test data
const data = {
    name: 'monday',
    age: 18,
    info: {
        city: 'FuZhou',
        a: {
            b: {
                c: {
                    d: {
                        e: 100
                    }
                }
            }
        }
    }
}

const proxyData = reactive(data)

We verify the data on the console:

As can be seen from the above figure, if the response expression is implemented by proxy, if it encounters an array that needs deep recursion, it will not be deep recursion like defineProperty. When will it get and when will it be deep recursion. Essentially, it is the layer you get that triggers the response. If you can't get the deep layer, it won't trigger the response. From the code, we can see that if the data is duplicate when the proxy modifies the attribute, it will not be processed. If the data is not repeated, process it again. In this way, the performance of the software is greatly improved.

2. Proxy summary

Now let's summarize the contents of the above Proxy:

(1) Deep monitoring, better performance

defineProperty is a one-time recursive completion; When Proxy get s and when it recurses deeply.

(2) Can listen for adding / deleting attributes

In vue2, defineProperty cannot add / delete properties. It needs to cooperate with Vue Set and Vue Delete. In Vue3, Proxy can add and delete attributes without special processing.

(3) Can listen for array changes

In vue2, monitoring array changes requires special processing, and can only be completed by deep recursion at one time. In vue3, you can monitor the changes of the array, and when to get and when to recurse. You can't get the deep layer without triggering the response.

3. Comparison between the two

At this point, let's put the object in vue2 Make a comparison between defineproperty and Proxy in vue3:

  • Proxy can avoid object Defineproperty problem;
  • Proxy is not compatible with all browsers (such as IE11) and cannot polyfill.

V 🟪 Concluding remarks

To some extent, vue3's Proxy does bring some benefits, but it also brings some problems. Because of this, the object of vue2 Defineproperty will exist for a long time. Therefore, the use of new technologies will always go through a process from trial stage to stable stage.

This is the end of the response principle of vue3! If you have any questions or the article is wrong, you are welcome to leave a message or private letter in the comment area~

  • Pay attention to the public Monday research room. Dry cargo official account for the first time.
  • If this article is useful to you, remember to click three times before you go!
  • See you next time! 🥂🥂🥂

Topics: Javascript Front-end Vue Proxy