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

Meta viewport makes the web page full screen display control on iPhone

In desperation, I suddenly thought, how is the Sin...

61 Things Every Web Developer Should Know

Normally, you'll need to read everyone's s...

Beginners learn some HTML tags (1)

Beginners can learn HTML by understanding some HT...

How to operate json fields in MySQL

MySQL 5.7.8 introduced the json field. This type ...

Implementing a table scrolling carousel effect through CSS animation

An application of CSS animation, with the same co...

Usage of mysql timestamp

Preface: Timestamp fields are often used in MySQL...

Tutorial on how to install and use Ceph distributed software under Linux

Table of contents Preface 1. Basic Environment 1....

Detailed explanation of how to find the location of the nginx configuration file

How can you find the location of the configuratio...

mysql create database, add users, user authorization practical method

1. Create a MySQL database 1. Create database syn...

JS cross-domain solution react configuration reverse proxy

Cross-domain solutions jsonp (simulate get) CORS ...

CSS navigation bar menu with small triangle implementation code

Many web pages have small triangles in their navi...