The responsivity principle of VUE3

Do the response:

// let vdata = reactive(data)Copy the code

The difference between vue2 and VUe3 is as follows:

1. Vue2 (dynamically adding and deleting attributes does not work)

2, arrays,

3. Initializing deep recursion is slow

4. The new data structure does not support Map and SET

About using the Proxy class

How does the following function work first

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      const val = Reflect.get(obj, key)
      return typeof val === 'object' ? reactive(val) : val
    },
    set(target, key, val) {
      // console.log(`set: ${key}`)
      const ret = Reflect.set(target, key, val)
      return ret
    },
    deleteProperty(target, key) {
      // console.log(`delete: ${key}`)
      return Reflect.deleteProperty(target, key)
    },
  })
}

const state = reactive({
  msg: 'hello world'.obj: { msg: 10 },
})

state.msg
state.foo = 'hello hui'
delete state.msg
console.log(state.msg)
console.log(state.obj.msg)
// get: msg
// set: foo
// delete: msg
// get: msg
// undefined
// get: obj
// get: msg
/ / 10
Copy the code

About reactive code implementation

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      const val = Reflect.get(target, key)
      track(target, key)
      return typeof val === 'object' ? reactive(val) : val
    },
    set(target, key, val) {
      // console.log(`set: ${key}`) 
      / / start the trigger
      const ret = Reflect.set(target, key, val)
      trigger(target, key)
      return ret
    },
    deleteProperty(target, key) {
      // console.log(`delete: ${key}`)
      trigger(target, key)
      return Reflect.deleteProperty(target, key)
    },
  })
}

const effectStack = []
/ / map
const targetMap = new WeakMap(a)function effect(fn) {
  const e = createReactiveEffect(fn)
  // Perform an immediate processing error into the effectStack
  e()
  return e
}

function createReactiveEffect(fn) {
  const effect = function () {
    try {
      effectStack.push(effect) / / in the
      return fn() / / execution
    } finally {
      effectStack.pop()
    }
  }
  return effect
}

Weekmap (object mapping to obtain map) map(key value mapping set) Set collects effect events
function track(target, key) {
  // Try to get the effect function
  const effect = effectStack[effectStack.length - 1] // take the last one
  if (effect) {
    let depMap = targetMap.get(target) / / get the map

    if(! depMap) {// If not, collect it for the first time
      depMap = new Map()
      targetMap.set(target, depMap) // Insert targetMap if it doesn't exist
    }
    let deps = depMap.get(key) / / get the set
    if(! deps) { deps =new Set()
      depMap.set(key, deps)
    }
    deps.add(effect) // Collect dependencies}}// Dependency triggers
function trigger(target, key) {
  let depMap = targetMap.get(target) / / get the map
  if (depMap) {
    let deps = depMap.get(key)
    deps.forEach((fn) = > {
      fn()
    })
  }
}

Copy the code

The demo test:

const state = reactive({
  msg: 'hello world',
  obj: { msg: 10 },
})

effect(() => {
  state.msg
  console.log(state.msg)
})

state.msg = 'hello boy'
Copy the code

HTML test:

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, Initial scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <div id="title"></div> </div> <script src="./index.js"></script> <script> const data = reactive({ title: }) const dom = document.getelementById ('title') effect(() => {dom.textContent = data.title}) setInterval(()  => { data.title = new Date().toString() }, 1000) </script> </body> </html>Copy the code

The Run-time code module understands watch and computed implementations