Vue2 Core Principles (Easy version)- Dependency collection

The responsive data principle of Vue

  • If you read the official document carefully, you’ll find this:

    One of the most unique features of Vue is its non-invasive responsive system. Data models are just plain old JavaScript objects. And when you modify them, the view is updated.

    This sentence seems very cool, but it doesn’t say anything 😓. As you modify them, the view is updated. But you should be sensitive to this sentence, but how to update? Ha ha, think carefully, the first two lessons (the first two articles reactive, template compilation) have helped us achieve the following two points:

    1. By observing the data, we know when the data was modified and when it should be updated.
    2. Views update DOM nodes by template compilation.
  • So what if I asked you to say something about responsive data? Note that I’m not just referring to reactive data in vue.js.

    In my opinion, data can inform us of its behavior in the process of producing changes (reading and writing) and enable us to make a series of responses to these behaviors. Such data is called responsive data.

    Ok, so back to vue.js, how do you have the ability to react to data as it changes? This is essentially the core defineReactive, which is implemented in JS as Object.defineProperty. Again, what is notification? In the last completed code, we tried to change the data in the data model:

    <body>
      <p>p1 - {{name}}</p>
    </body>
    <script>
    let vm = new Vue({
      el: '#app'.data() {
        return {
          name: 'vue',}}})setTimeout(() = > {
      vm.name = 'vue3'
    }, 1000)
    </script>
    Copy the code

    Results:Ha ha, nothing happened! No, we already know that name changed from ‘vue’ to ‘vue3’, but we didn’t tell our _render function that we need to render again (update).

    From this, we have today’s topic, dependent collection!

Vue’s responsive data dependency collection

Update the view

To call the render function and update the view, here’s what we did before:

// This function is called again when the data changes
let updateComponent = () = > {
    // Call the render function to generate the virtual DOM
    vm._update(vm._render()); // The updateComponent method can be called for subsequent updates
    // Use the virtual DOM to generate the real DOM
}
updateComponent();
Copy the code

As you can see, since we only called updateComponent once in the mount phase, any subsequent changes we make to the data will not trigger render again and the view will not be updated. So do we need a way to do this automatically for us?

Observer model

L Ä› I le lÄ› I le:

The observer pattern is one of the software design patterns. In this mode, a target object manages all observer objects that depend on it and actively notifies itself of changes in its state. This is usually done by calling the methods provided by each observer.

What does that mean? In vue.js, that is to say, add an observer to each component page, add an instance of that observer to every target we want to listen on in our data, and let that observer store all dependencies. This allows the observer to be notified when a dependency changes behavior.

A. The dependent data is the observation target. B. Views, calculated properties, and listeners are observers

Implementation of the observer pattern

Render => “touch” => data.getter => Collect as Dependency This means that in the initial phase, the required responsive data collection becomes a dependency of the current component. This is what we call a dependency collection. So at this point, you can see why we do dependency collection? Only when a dependency collection is collected can it correspond to that observer and can the render function be called in real time to update the view. So, how do you do that?

// updateComponent();
// Observer mode: property is "observed" refresh page: "Observer"
new Watcher(vm,updateComponent,() = >{
    console.log('Updated view')},true); // He is a render Watcher with other watcher to follow
Copy the code

The first step is to replace the updateComponent we did manually with a new Watcher instance of the current page. So this page corresponds to an observer.

Second, every object/property that is dependent on the template should subscribe to the current observer.

// Object.defineProperty
 get(){
    // I want to match watcher with dep
    if(Dep.target){ // This value is specified in the template
        dep.depend() // Make deP remember Watcher
        // Can be arrays can be objects, objects also need to collect dependencies,
        // The $set method needs to trigger its own update
        if(childOb){ 
            // Let arrays and objects also record watcher
            childOb.dep.depend(); 
            // The outer array is collected by dependency collection
            if(Array.isArray(value)){ dependArray(value); }}}return value
},
Copy the code

The current observer, in turn, records its own dependencies in reverse.

depend(){
  // Dep.target  
  // Dep = dep, dep = deP
  if(Dep.target){
    Dep.target.addDep(this); }}Copy the code

At this point, if a dependency changes, we let it notify its observers and react. That is, the re-render component.

// observer/index.js => Object.defineProperty
set(newV){ 
  if(newV ! == value){// If the user assigns a new object, the object needs to be hijacked
    observe(newV); 
    value = newV;
    // Tell the current property to store watcher executiondep.notify(); }}// observer/dep.js => notify
notify(){
  this.subs.forEach(watcher= >watcher.update());
}

// observer/watcher.js => update
update(){ // Update operations in VUE are asynchronous
 // Every time you update this
 // I want to cache watcher and update it later
 queueWatcher(this); 
}    
Copy the code

I have drawn a mind map and a flow chart, please read it carefully:

The 🎉

Next lecture, asynchronous update