Vue learning notes: understand how Vue2 solves the responsive problem of arrays and objects

preface

Vue2 monitors data and view changes by using Object... defineProperty to set data getters and setters. For reference types such as arrays and objects, getters and setters cannot detect their internal changes. So is vue2 to solve this problem?
Through a simple example to understand how to solve the responsive problem of arrays and objects in Vue2.

Basic code

<html>

<head>

</head>

<body>
  <script>
    //1. Define a data object to simulate the data in the component
    var data = {
      name: 'xwd',
      sex: 1,
      dog: {
        name: 'peter',
        age: 5
      },
      hobby: [
        "pingpang", "basktetball"
      ],

    }
	//2. Reactivate Data
    Observer(data)
	
    function Observer(data) {
		// Simulate component initialization to reactivate data
      if (typeof data != "object" || data == null) {
        return data
      }
      for (let item in data) {
        //Responsive data
        defineReactive(data, item, data[item])
      }
      return data
    }
	
    function defineReactive(target, key, value) {
      Object.defineProperty(target, key, {
        enumerable: false,
        configurable: false,
        get() {
		//Simulate the rendering of the view with the print console
          console.log("View rendering uses data")
          return value;
        },
        set(newValue) {
          if (newValue !== value) {
	
            value = newValue;
		    //Simulate data change view update with print console
            console.log("update the view")
          }

        }
      })

    }
	
  </script>
</body>

Processing of complex objects

Changes to the properties of complex objects mainly include the following:

  1. Changes of object attributes in complex objects

    Vue2's processing method is to deeply traverse the properties of the Data object during response until getter s and setter s are added to all basic types of properties.

  function defineReactive(target,key,value) {
      Observer(value)
      Object.defineProperty(target,key,{
        enumerable: false,
        configurable: false,
        get() {
          console.log("View rendering uses data")
          return value;
        },
        set(newValue) {

          if (newValue !== value) {
            value = newValue;
            console.log("update the view")
          }

        }
      })

    }
  1. set a new object to the property of the data

    When set ting a new object, the update view will be displayed, but the value of the newly added object will not be added with a response.
    The processing method of Vue2 is to perform defineReactive operation on the attribute again during set, and add getter s and setter s to the attribute.
set(newValue) {
  Observer(value)
  if (newValue !== value) {
    value = newValue;
    console.log("update the view")
  }
}

Note: because Vue2 adds the data response at the beginning of initialization and set attribute, when the data attribute is added or deleted during use. Vue cannot add a response. If you want to respond to the attributes added during the run, you must use the Vue.delete method or Vue.Set.

Processing of Array

Changes within the array, including the use of our commonly used array functions, push, pop, etc. Can not be detected by the setter function. It will be detected only when the whole array is replaced.

Vue2 solves this problem by providing a new set of Array variograms. Replace the prototype of Array and use a new variogram to update the view in the user-defined variogram.

  1. Create a new template object based on the original Array prototype
const oldArrayProto = Array.prototype;
    const newArrProto = Object.create(oldArrayProto);
  1. Rewrite the array variogram such as push pop of the new template
    ['push', 'pop'].forEach(methodName => {
      newArrProto[methodName] = function () {

        console.log("update the view")
        oldArrayProto[methodName].call(this, ...arguments)
      }
});
  1. Replace the prototype of the Array object in data in the scan
  if (Array.isArray(data)) {
    data.__proto__ = newArrProto
  }

Note: Vue cannot detect changes in the following arrays:

  1. When you directly set an array item using an index, for example: vm.items[indexOfItem] = newValue
  2. When you modify the length of the array, for example: vm.items.length = newLength

resolvent

Complete code

<html>

<head>

</head>

<body>
  123
  <script>
    //1. Define a data object to simulate the data in the component
    var data = {
      name: 'xwd',
      sex: 1,
      dog: {
        name: 'peter'
        ,
        type: 'dog'
      },
      hobby: [
        "pingpang", "basktetball"
      ],

    }
    const oldArrayProto = Array.prototype;
    const newArrProto = Object.create(oldArrayProto);

    ['push', 'pop'].forEach(methodName => {
      newArrProto[methodName] = function () {

        console.log("update the view")
        oldArrayProto[methodName].call(this, ...arguments)
      }
    });

    Observer(data)


    function Observer(data) {
      if (typeof data != "object" || data == null) {
        return data
      }
      if (Array.isArray(data)) {
        data.__proto__ = newArrProto
      }
      for (let item in data) {
        //Responsive data
        defineReactive(data, item, data[item])
      }
      return data



    }
    function defineReactive(target, key, value) {
      Observer(value)
      Object.defineProperty(target, key, {
        enumerable: false,
        configurable: false,
        get() {
          console.log("View rendering uses data")
          return value;
        },
        set(newValue) {
          Observer(value)
          if (newValue !== value) {
            value = newValue;
            console.log("update the view")
          }

        }
      })

    }


  </script>
</body>



</html>

Remaining problems

Use Object.defineProperty to listen for data and view changes. When complex objects are encountered, it is necessary to deeply traverse all objects to set getter and setter functions for the properties, which will lead to slow loading speed on the first screen. To solve this problem, Vue3 implements the response by
Object.defineProperty is replaced by Proxy. When the data needs to be used, the response is added to improve the loading speed of the first screen.

References

1. (full version) quickly master Vue2 responsive principle [Vue]_ Beep beep beep_ bilibili
2. Deep responsive principle - Vue.js (vuejs.org)

Keywords: Front-end Vue Vue.js

Added by genista on Sun, 24 Oct 2021 15:46:09 +0300