Sobes.tech
Middle

Как работи реактивността във Vue.js?

sobes.tech AI

Отговор от AI

Реактивността във Vue.js се основава на патерна "наблюдател" (Observer).

Когато се създаде инстанция на Vue, тя преминава през всички свойства на обекта data и ги преобразува в гетъри и сетъри, използвайки Object.defineProperty във Vue 2 или Proxy във Vue 3.

Vue 2:

  • При достъп до свойство (гетър), Vue следи кой компонент го използва.
  • При промяна на свойство (сетър), Vue уведомява всички компоненти, които го следят, за необходимостта от обновяване (преоразмеряване на шаблона).

Vue 3:

  • Използва Proxy за прихващане на всички операции с обекта (добавяне, премахване на свойства, промяна на стойности и т.н.), осигурявайки по-пълна реактивност в сравнение с Vue 2.
  • Благодарение на Proxy, реактивността във Vue 3 няма ограничения като във Vue 2 (не е необходим $set за добавяне на нови свойства).

Ключови компоненти на реактивността:

  • Observer: Преобразува свойствата на данните в гетъри/сетъри (Vue 2) или ги обработва с Proxy (Vue 3).
  • Dep (зависимост): Обект, свързан с всяко реактивно свойство, който съхранява списък с зависими Watcher-и.
  • Watcher: Представлява компонент, изчисляемо свойство или watchers, които зависят от реактивните данни. Когато данните се променят, Watcher-ът е уведомяван и изпълнява съответното действие (например, преоразмеряване на компонента).

Пример (Vue 2):

// Вътрешна реализация (опростена)
function defineReactive(obj, key, val) {
  let dep = new Dep(); // Създаваме Dep за свойството

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      // Ако има глобален Watcher (при рендиране на компонента)
      if (Dep.target) {
        dep.depend(); // Добавя Watcher към списъка с зависимости на Dep
      }
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      val = newVal;
      dep.notify(); // Уведомява всички зависими Watcher-и
    }
  });
}

// Как изглежда в компонент
new Vue({
  data: {
    message: 'Hello' // defineReactive ще бъде приложено към message
  },
  template: '<div>{{ message }}</div>' // При достъп до message, Watcher-ът на този шаблон ще бъде добавен към Dep message
});