The use and principle of Vue.set (analysis of source code series)

Analysis source code series-Vue.set / vm.$setDetailed

Function and concept description

Official document: Vue-set

Add a property to the responsive object and ensure that this new property is also responsive and triggers the view update. It must be used to add new properties to the reactive object, because Vue cannot detect ordinary new properties (such as this.myObject.newProperty ='hi')

Limitations It is
not allowed to dynamically add root-level responsive attributes. such as:

// 错误写法
this.$set(this, 'newkey', 1111)

// 正确写法
this.$set(this.obj, 'newkey', 111)

// 取值: this.obj.newkey => 111

summary

  • Vue.setAnd vm.$setmethods are actually the same, but the wording is not the same
  • The effect is to dynamically add attributes to the page, and the dynamically added attributes are also responsive attributes

Why use set to add responsive attributes

Look at vue Responsive principle: vue two-way data binding principle
can be seen in fact rely on a responsive Object.defineProperty
and Object.definePropertyjust listen to one of the attributes of an object, if there are multiple properties needs to listen

Look at a demo to understand:

var data = {
    
    }

Object.defineProperty(data, 'data1', {
    
    
  get: function() {
    
    
    console.log('get data1')
    return this.value
  },
  set: function(newVal) {
    
    
    console.log('set data1')
    this.value = newVal
  }
})

data.data1 = 111 // 将会打印 set data1
console.log(data.data1) // 先打印 get data1  然后才是 111

data.data2 = 222 // 无打印,无报错
console.log(data.data2) // 直接打印222。表示没有进过 `Object.defineProperty`

Start looking at the source code

Here is a demo for debugging

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
  var app = new Vue({
     
     
    el: '#app',
    data: {
     
     
      addData: {
     
     }
    }
  })
  debugger
  app.$set(app.addData, 'newkey', 1111)
</script>

The first to enter the $setmethods of the time, first came to the default value section, this time to return a null value, after the return, re-enter $setis the part we need to debug

In debug mode, enter the set method

Line 2 1081 a method for detecting the data type of the target node, i.e. $setthe detection of the first parameter

  • 1085-1089 determine the type of the array. After all, because the special type Object.defindPropetycannot detect the change of the array, the change of the array is updated manually.
  • 1090-1093 is to determine whether the attribute already exists before, and there is no need to repeat the monitoring if it exists
  • 1095--1100 is to determine the root node can not this.databe directly added to the data
  • Note that 1094 row variable obis observed (observer) for short. It is also used to determine whether the variable has been monitored
  • The values ​​that have been monitored and do not need to be repeatedly monitored will be directly returned to the corresponding ones val. It also $setreturns a return value of the current
  • If the object is new, then it went to the 1106 line defineReactive$$1method

Add a listener defineReactive$$1method

  • 1021 initialize new Dep view the analysis of dep look dep analysis is necessary. This involves many of the following processes. The csdn does not support hash navigation, so you need to manually slide it down and take a look~
  • 1023-1026 Determine whether the object is readable and writable
  • 1019--1033 get on the target object getand setmethod.
  • 1035 There is a shallow variables in our previous code in this variable does not exist !shallowthat is true. Therefore, the implementation of a observemethod to view observe analysis csdn does not support the hash navigation, you need to manually slide down under their own to see ~
  • After reading the above observeanalysis, we know observethat property for his son, cycling add listening.
  • Line 1039 is bound to the event that gets the attribute value. When getting the corresponding value, I Dep.targetjust saw it as a global observer watch. So, if there is dep.targetcall a target for the current dependmethod, which is from Depthe inherited. It is equivalent to register a callback to watch the event (which is estimated watchand computeda foreshadowing buried)
  • 1052 start line setmethod. Also start their own getterto get the current value inside
  • Line 1069, if we are copying an object newly, he has to re-add a data hold for these objects in a loop, if it has already been held, it can be skipped, which is the code above
  • The last 1070 lines are called after set dep.notify(). It stores the time when the corresponding object update needs to be triggered (subscription observer mode). Now that the value is updated, it is triggered to the relevant subscription function (watch is also triggered at this time, and the view is also updated at this time) . And we have to get the set value before the front, so the watchmethods inside newValand oldValis being recorded at this time
  • Finally, the current value is returned, $setand the execution of the method is over



dep analysis

The dep code is not very long. dep is equivalent to a subscription center

  • In line 717, you can see that each dep has a corresponding ID, and it is self-increasing
  • Line 718 can be regarded as an event center, and all monitoring is stored here
  • You can see that there are several methods on the dep prototype addSub removeSub depend notify. They are all used to operate the corresponding monitor, add/delete, find the corresponding dependency, and notify these methods
  • 725 line Dep.targethas very detailed notes, globally unique viewer

The core is remember a few addSub removeSub depend notifymethods. Then continue to look at the code just now

observe analysis

Especially thoughtful notes

Attempt to create an observer instance for a value,
try to create value for the observer instance
returns the new observer if successfully observed,
if successfully observed, the new viewer is returned
or the existing observer if the value already has one.
Or existing Observer of (if the value already contains one)

  • It seems value.__ob__if there is, then this property would have been an observer, and this is our $setfirst step in a judgment as to __ob__the

  • Then distinguish the array, the array does not have observers

  • Mainly to see the 1003 line, create a new observer new Observenote the capital, not the current object

  • new Observe In Figure 2 below, I won’t talk about it separately.

  • 926 lines. To __ob__add properties, make no mistake, and __ob__set it to a non-enumerable type. For details, you can see the code that goes in 926

  • 927-933 are all for array operations

  • Line 935, the walk method of the current object. Pasting the code directly, we can see that it is a loop, traversing our object once, and calling it for each object defineReactive$$1. As you can see, this method will only be called if the value is an object type.

  • Since it is called defineReactive$$1. Then a recursion is formed here, the head of the recursion is to stop calling when the attribute is no longer an object defineReactive$$1.

  • After seeing this, the next step should go back to add a method to listen defineReactive $$ 's 1035 line

/**
 * Walk through all properties and convert them into
 * getter/setters. This method should only be called when
 * value type is Object.
 */
Observer.prototype.walk = function walk(obj) {
    
    
  var keys = Object.keys(obj)
  for (var i = 0; i < keys.length; i++) {
    
    
    defineReactive$$1(obj, keys[i])
  }
}

to sum up

  • vue responsive principle relies on Object.defindPropetythe getand setmethods, respectively, in these two methods to trigger the corresponding event

  • Because of JS and Object.defindPropetyrestrictions that can not be dynamically added need to monitor the property, so we must use Vue.set()the method

  • Vue.set()Inside the method is a cyclic processing process. If the new monitor is an object, it will continue to call itself to form a recursion, until the last sub-attribute is a 数组/非对象类型parameter, the recursion ends, and then add a monitor for yourself, in the monitor It will trigger other related methods (events subscribed in Dep will be triggered). Form our common two-way data binding

  • Since the Object.defindPropetychange can only monitor the object, so the value of a particular index within the array change is not listening to, so should be used Vue.setto manually trigger an update, this time Vue.setonly do the updated value, and will not repeat New Increase monitoring

Original starter: Analysis Source Series - Vue.set / vm.$setDetailed This is a new blog address, interested can look at

Guess you like

Origin blog.csdn.net/Jioho_chen/article/details/107005845