Vue2 core Principle (simple version)- Watch function realization

What is a watch used for?

Vue provides a more generic way to respond to changes in data with the Watch option. This approach is most useful when asynchronous or expensive operations need to be performed when data changes.

What is a watch?

An object whose key is the expression to observe and whose value is the corresponding callback function. The value can also be a method name, or an object that contains options. The Vue instance will call $watch() at instantiation time, iterating through each property of the Watch object. Document delivery

Example:

/ / define the watch
let vm = new Vue({
  el: '#app'.data() {
    return {
      name: 'vue2'}},watch: {
    name(newVal, oldVal) {
      console.log(`watch name change form ${oldVal} to ${newVal}`); }}})/ / change the name
setTimeout(() = > {
  vm.name = 'vue3'
}, 1000)
// Console prints
// watch name change form vue2 to vue3
Copy the code

How to make the watch?

  1. First, we’ll review the principles and implementation of vUE dependency collection, as shown in my previous article, dependency Collection.

The core principle is to add a custom Watcher to all the properties in the Watch object passed in Vue Options, collect the dependency of the corresponding property, and then notify not only its rendering Watcher but also the current custom Watcher when the dependency is updated. To call your defined callback, complete the logic inside the function.

  1. How to get newValue and oldValue when updating?

First, the default watcher binding is to execute the this.get method, so we do the same thing we did in rendering Watcher, which is to ‘touch’ the property, make the dependency feel dependent, add the subscriber, and then the value is the initial value. We log it to watcher, this.value = this.get(); . Each time the update method is called on watcher, we will call this.get again. Plus the this.value we recorded earlier, great, we have newValue and oldValue!

  1. Code implementation

    A. Initialize the Watch object
    // Add $watch mixin
    export function stateMixin(Vue) {
      Vue.prototype.$watch = function (key, handler, options = {}) {
        const vm = this;
        options.user = true;
        new Watcher(vm, key, handler, options);
      };
    }
    // Add a custom watcher to the passed watch
    function initWatch() {
      const vm = this;
      let watchs = vm.$options.watch;
      for (let key in watchs) {
        let handler = watchs[key];
        if (Array.isArray(handler)) {
          for (let i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i]); }}else{ createWatcher(vm, key, handler); }}}function createWatcher(vm, key, handler) {
      vm.$watch(key, handler);
    }
    Copy the code

    B. Modify the Watcher class to handle custom Watcher properties

    // observer/watcher.js 
    constructor(vm, exprOrFn, cb, options) {
      this.id = "watcher-" + id++;
      this.vm = vm;
      this.exprOrFn = exprOrFn;
      this.cb = cb;
      this.deps = [];
      this.depsId = new Set(a);this.options = options;
      this.user = !! options.user;if (typeof exprOrFn === "string") {
        this.getter = function () {
          let path = exprOrFn.split(".");
          let obj = path.reduce((pre, currentPath) = > {
            return pre[currentPath];
          }, vm);
          return obj;
        };
      } else {
        this.getter = exprOrFn;
      }
    
      this.value = this.get();
    }
    
    get() {
      pushTarget(this);
      // Record the old value
      const value = this.getter.call(this.vm);
      popTarget(this);
      // Return the old value
      return value;
    }
    
    update() {
      // Update operations in VUE are asynchronous
      // I want to cache watcher and update it later
      queueWatcher(this); 
    }
    
    run() {
      const oldValue = this.value;
      const newValue = this.get();
    
      if (this.user) {
        this.cb(newValue, oldValue);
        // Remember to record the new value as the old value for the next time
        this.value = newValue; }}Copy the code

The complete code

Github.com/Sotyoyo/do-… Branch do – watch

The original link

If you are reading this article at a non-nuggets address, here is the original portal, your likes are the biggest support for me!

The 🎉

Next lecture, computed property implementation