Sobes.tech
Middle

¿Cómo funciona la reactividad en Vue.js?

sobes.tech AI

Respuesta de la IA

Реактивность во 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 (Dependency): Объект, ассоциированный с каждым реактивным свойством, который хранит список зависимых 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 этого template добавится в Dep message
});