What is reactive?

Track changes in data and perform certain actions when the data is accessed.

Vue2

When you pass a JS Object to a Vue instance as a data option, Vue iterates through all of the Object’s attributes and converts them to getters/setters using Object.defineProperty(). These gettet/ setters are invisible to the user, but internally they allow Vue to track dependencies and notify properties of changes when they are modified.

Object.defineProperty

So we need to figure out how to use Object.defineProperty first:

let obj = {
  a: 0
}

Object.defineProperty(obj, 'a', {
  get: () = > {
    console.log('get') // The action to perform when getting attribute A
    return a
  },
  set: (newVal) = > {
    console.log('set') // Action to perform when setting property A
    a = newVal
  }
})

obj.a = 100 / / output 'set'
obj.a / / output 'get'
Copy the code

encapsulation

Then simply encapsulate it:

Now we have a known complex object obj:

let obj = {
  a: 0.b: [1.2.3].c: {
    d: 4}}Copy the code

Let’s design an observe function to make obj responsive:

observe(obj) // Pass obj to observe to achieve obj responsiveness
Copy the code

Observe function:

function observe(data) {
  if(! data ||typeofdata ! = ='object') {
    return
  }
  for (var key in data) {
    let val = data[key]
    Object.defineProperty(data, key, {
      enumerable: true.// The current key is enumerable
      configurable: true.// The current key is configurable (modifiable, deletable...)
      get: () = > {
        console.log('get') // The action to perform when getting the property
        return val
      },
      set: (newVal) = > {
        console.log('set') // Action to perform when setting properties
        val = newVal
      }
    })
    if (typeof val === 'object') {
      observe(val) // Continue to call observe (deep traversal) if the property is also an object}}}Copy the code

After observing (obj), a, b, b[0], b[1], b[2], c, and c.d in obj are all responsive. However, if it is a new attribute, such as obj.e or obj.b[3], it is not reactive.

Vue3

Proxy

Upgraded from Object.defineProperty to Proxy

Proxy objects are used to create a Proxy for an object to intercept and customize basic operations (such as property lookup, assignment, enumeration, function calls, and so on)

Let’s take a look at how Proxy is used:

let obj = {
  a: 0
}

let handler = {
  get(target, prop) {
    console.log('get') // The action to perform when getting the property
    return Reflect.get(... arguments)// return target[prop]
  },
  set(target, key, value) {
    console.log('set') // Action to perform when setting properties
    return Reflect.set(... arguments)// return target[key] = value}}let proxy = new Proxy(obj, handler) // Proxy object obj

proxy.a / / output 'get'
proxy.a = 1 / / output 'set'
Copy the code

encapsulation

Then simply encapsulate it:

let obj = {
  a: 0.b: [1.2.3].c: {
    d: 4}}function reactive(data) {
  let handler = {
    get(target, prop, receiver) {
      console.log('get') // The action to perform when getting the property
      let value =  Reflect.get(... arguments)if (typeof value === 'object') {
        return reactive(value) // If the property is also an object, continue to call Reactive for the proxy
      } else {
        return value
      }
    },
    set(target, key, value, receiver) {
      console.log('set') // Action to perform when setting properties
      return Reflect.set(... arguments) } }return new Proxy(data, handler)
}

let proxy = reactive(obj) // Proxy object obj
Copy the code

After reactive(obj) is executed, a, b, b[0], b[1], b[2], c, and c.d in the proxy object are all reactive. And if there are new attributes, such as proxy.e or proxy.b[3] is also responsive.