Sobes.tech
Middle

How does reactivity work in Vue.js?

sobes.tech AI

Answer from AI

Reactivity in Vue.js is based on the "Observer" pattern.

When a Vue instance is created, it walks through all properties in the data object and converts them into getters and setters using Object.defineProperty in Vue 2 or Proxy in Vue 3.

Vue 2:

  • Accessing a property (getter) makes Vue track which component uses it.
  • Changing a property (setter) notifies all components that depend on it to update (re-render the template).

Vue 3:

  • Uses Proxy to intercept all operations on the object (adding, deleting properties, changing values, etc.), providing more complete reactivity compared to Vue 2.
  • Thanks to Proxy, Vue 3's reactivity has no limitations like Vue 2 (no need for $set to add new properties).

Key components of reactivity:

  • Observer: Converts data properties into getters/setters (Vue 2) or handles them with Proxy (Vue 3).
  • Dep (Dependency): An object associated with each reactive property that holds a list of dependent Watchers.
  • Watcher: Represents a component, computed property, or watcher that depends on reactive data. When data changes, the Watcher is notified and triggers the appropriate action (e.g., re-rendering the component).

Example (Vue 2):

// Internal implementation (simplified)
function defineReactive(obj, key, val) {
  let dep = new Dep(); // Create a Dep for the property

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      // If there is a global Watcher (during component rendering)
      if (Dep.target) {
        dep.depend(); // Add Watcher to Dep's dependency list
      }
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      val = newVal;
      dep.notify(); // Notify all dependent Watchers
    }
  });
}

// How it looks in a component
new Vue({
  data: {
    message: 'Hello' // defineReactive will be applied to message
  },
  template: '<div>{{ message }}</div>' // Accessing message will add the Watcher of this template to the message's Dep
});