Mind mapping

preface

In the last article we went through the process of rendering individual root component data to the page. Vue source preliminary exploration (three) single component mount (rendering).

Now let’s do one thing, change the properties and manually call the _update() function to make the page trigger an update. We noticed that the page has also been updated.

<body>
  <div id="app">
    <li>{{name}}</li>
    <li>{{age}}</li>
  </div>
  <script src="./vue.js"></script>
  <! -- < script SRC = "https://cdn.jsdelivr.net/npm/[email protected]" > < / script > -- >
  <! -- <script src="./test.js"></script> -->
  <script>
    var vm = new Vue({
      el: '#app'.data: {
        name: 'Ming'.age: 20
      }
    })
  
    vm.name = 'morning'

    vm._update(vm._render())
  </script>
</body>
Copy the code

The body of the

Rely on collection and trigger updates

function defineReactive(data, key, value){
  // If the key of the current object is another object, perform deep monitoring
   
  // Add a dep to each attribute
  let dep = new Dep()

  observe(value)
  Object.defineProperty(data, key,{
    get() {
      if(Dep.target){  //dep.target now saves watcher
        dep.depend()
      }
      return value
    },
    set(newValue) {
      // If the new value is equal to the old value, no processing is done
      if(value === newValue) return
      // If an object is set, the new object is hijacked again.
      observe(newValue)
      value = newValue
      // Tell all watcher updates are available
      dep.notify()
    }
  })
}
Copy the code

Dep for each attribute

let id = 0;

class Dep{
  constructor() {  // Put watcher in deP
    this.subs = []
    this.id = id++
  }


  depend() {
    Dep.target.addDep(this)  // Make Watcher remember deP
  }

  addSub(watcher){ // Make deP remember Watcher
    this.subs.push(watcher)
  }

  notify(){
    this.subs.forEach((watcher) = >{
      watcher.update()
    })
  }
}

// Make a mark to store watcher
Dep.target = null  // Create a global variable, a static attribute

export default Dep
Copy the code

Watcher per view

import Dep from "./dep"

let id = 0
class Watcher {
  constructor(vm, fn, cb, options) {
    this.vm = vm;
    this.fn = fn;
    this.cb = cb;
    this.options = options;
    this.id = id++;
    this.depsId = new Set(a)this.deps = [] / / store dep

    this.getter = fn;   //fn is the external render logic
    this.get();   // Do component rendering for the first time
  }
  addDep(dep) {
    let did = dep.id  
    if(!this.depsId.has(did)){
      this.depsId.add(did)
      this.deps.push(dep)

      dep.addSub(this) // Make deP remember Watcher}}get() {
    // Perform render logic
    Dep.target = this;
    this.getter(); // When executing the render logic, invoke the render function, which triggers the get function in the data response
    Dep.target = null;
  }

  update() {
    // Will be updated several times
    console.log('update')
    this.get()
  }

}

export default Watcher
Copy the code

Dep and Watcher diagram

conclusion

  1. Vue uses observer mode. The default component creates a Watcher when rendering (and renders the view).
  2. Let the deP of the property record the current watcher when the render function passes the get method in the response.
  3. Also remind Watcher of this DEP (not yet used) because deP and Watcher are many-to-many, because one property may correspond to multiple views, and one view to multiple data.
  4. If the data changes, the DEP of the corresponding property is notified, which in turn notifies the stored Watcher to update the page.

Subsequent write operations are required when the same attribute value is modified multiple times on the page. nextTick()

Links to a series of articles (constantly updated…)

Vue source exploration (a) responsive principle

Vue source exploration (two) template compilation

A preliminary study of Vue source code (3) Single component mount (rendering)

Vue source exploration (four) dependent (object) collection process

Object asynchronous update nextTick()