Detailed explanation of Vue3's responsive principle

Detailed explanation of Vue3's responsive principle

Review of Vue2 responsive principles

// 1. Object responsiveness: traverse each key and define getter and setter
// 2. Array responsiveness: Override array prototype method and add additional notification logic const originalProto = Array.prototype
const arrayProto = Object.create(originalProto)
  ;['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].forEach(
    method => {
      arrayProto[method] = function () {
        originalProto[method].apply(this, arguments)
        notifyUpdate()
      }
    }
  )
function observe(obj) {
  if (typeof obj !== 'object' || obj == null) {
    return
  }
  // Add array type judgment, if it is an array, overwrite its prototype if (Array.isArray(obj)) {
    Object.setPrototypeOf(obj, arrayProto)
  } else {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i]
      defineReactive(obj, key, obj[key])
    }
  }
}
function defineReactive (obj, key, val) {
  observe(val) // Solve the nested object problem Object.defineProperty(obj, key, {
    get () {
      return val
    },
    set (newVal) {
      if (newVal !== val) {
        observe(newVal) // New value is an object val = newVal
        notifyUpdate()
      }
    }
  })
}
function notifyUpdate () {
  console.log('Page updated!')
}

Disadvantages of vue2 responsiveness:
The responsiveness process requires recursive traversal, which consumes a lot of resources. Newly added or deleted attributes cannot be monitored. Array responsiveness requires additional implementation.
Map, Set, Class, etc. cannot be modified responsively and have limited syntax

Analysis of Vue3 responsive principle

Vue3 uses the Proxy feature of ES6 to solve these problems.

function reactive(obj) {
  if (typeof obj !== 'object' && obj != null) {
    return obj
  }
  // Proxy is equivalent to adding interception to the outer layer of the object // http://es6.ruanyifeng.com/#docs/proxy
  const observed = new Proxy(obj, {
    get (target, key, receiver) {
      // Reflect is used to perform default operations on objects, which is more standardized and friendly. // Proxy and Object methods have corresponding Reflect methods. // http://es6.ruanyifeng.com/#docs/reflect
      const res = Reflect.get(target, key, receiver)
      console.log(`Get ${key}:${res}`)
      return res
    },
    set (target, key, value, receiver) {
      const res = Reflect.set(target, key, value, receiver)
      console.log(`Set ${key}:${value}`)
      return res
    },
    deleteProperty (target, key) {
      const res = Reflect.deleteProperty(target, key)
      console.log(`delete ${key}:${res}`)
      return res
    }
  })
  return observed
}
//Code test const state = reactive({
  foo: 'foo',
  bar: { a: 1 }
})
// 1. Get state.foo // ok
// 2. Set existing attribute state.foo = 'fooooooo' // ok
// 3. Set non-existent attribute state.dong = 'dong' // ok
// 4. Delete attribute delete state.dong // ok

Nested Object Responsiveness

Test: Nested objects are not responsive

// Set nested object properties react.bar.a = 10 // no ok

Add object type recursion

      // Extract helper method const isObject = val => val !== null && typeof val === 'object'
      function reactive(obj) {
        //Judge whether it is an object if (!isObject(obj)) {
          return obj
        }
        const observed = new Proxy(obj, {
          get (target, key, receiver) {
            // ...
            // If it is an object, recursion is needed return isObject(res) ? reactive(res) : res
          },
          //...
        }

Avoid duplicate agents

Repeating agents, such as

reactive(data) // Pure object that has been proxied
reactive(react) // proxy object

Solution : Cache the previous proxy results and use them directly when getting

const toProxy = new WeakMap() // same as obj:observed
      const toRaw = new WeakMap() // same as observed:obj
      function reactive(obj) {
        //...
        // Search cache to avoid duplicate proxy if (toProxy.has(obj)) {
          return toProxy.get(obj)
        }
        if (toRaw.has(obj)) {
          return obj
        }
        const observed = new Proxy(...)
        // Cache proxy results toProxy.set(obj, observed)
        toRaw.set(observed, obj)
        return observed
      }
      // Test effect console.log(reactive(data) === state)
      console.log(reactive(state) === state)

Summarize

This article ends here. I hope it can be helpful to you. I also hope you can pay more attention to more content on 123WORDPRESS.COM!

You may also be interested in:
  • Analysis of the implementation principle of v-model and responsiveness in Vue
  • Detailed example of Vue responsiveness principle
  • Vue3.0 responsive function principle detailed
  • Detailed explanation of the principles of Vue's responsive system
  • Detailed explanation of VUE responsiveness principle
  • Detailed explanation of the implementation of VUE responsive principle

<<:  About the layout method of content overflow in table

>>:  DIV and image horizontal and vertical centering compatible with multiple browsers

Recommend

VMWare virtual machine 15.X LAN network configuration tutorial diagram

Recently, I have been working on several virtual ...

Simple setup of VMware ESXi6.7 (with pictures and text)

1. Introduction to VMware vSphere VMware vSphere ...

Two methods to implement Mysql remote connection configuration

Two methods to implement Mysql remote connection ...

Springboot+Vue-Cropper realizes the effect of avatar cutting and uploading

Use the Vue-Cropper component to upload avatars. ...

Website User Experience Design (UE)

I just saw a post titled "Flow Theory and Des...

Solution to the blank page after vue.js packaged project

I believe that many partners who have just come i...

Vue implements infinite loading waterfall flow

This article example shares the specific code of ...

Detailed explanation of CSS style cascading rules

CSS style rule syntax style is the basic unit of ...

Axios cancel request and avoid duplicate requests

Table of contents origin status quo Cancel reques...

Mysql Chinese sorting rules description

When using MySQL, we often sort and query a field...

Detailed instructions for installing SuPHP on CentOS 7.2

By default, PHP on CentOS 7 runs as apache or nob...

Parsing Apache Avro Data in One Article

Abstract: This article will demonstrate how to se...

Sample code for implementing form validation with pure CSS

In our daily business, form validation is a very ...