Skip to main content

Як Vue відстежує зміни даних?

Як Vue відстежує зміни даних

Vue реалізує реактивну систему на основі Proxy (у Vue 3) або Object.defineProperty() (у Vue 2). Основна ідея - перехоплення доступу до властивостей об'єктів (читання і запис), щоб знати:

  • коли дані читаються -> зареєструвати залежність
  • коли дані змінюються -> сповістити залежні ефекти (компоненти, обчислювані властивості, watch тощо)

Механізм на рівні Proxy (Vue 3)

Коли ви створюєте реактивний об'єкт через reactive() або ref(), Vue огортає його за допомогою Proxy.

Приклад:

javascript
import { reactive, effect } from 'vue' const state = reactive({ count: 0 }) effect(() => { console.log(`Count: ${state.count}`) }) state.count++ // тригерить effect -> виводить "Count: 1"

Що відбувається крок за кроком:

  1. Створення Proxy
javascript
const proxy = new Proxy(target, { get(target, key, receiver) { track(target, key) // реєструє залежність return Reflect.get(target, key, receiver) }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver) trigger(target, key) // повідомляє підписників про зміну return result } })
  1. Функція track()
  • Викликається при читанні властивості (get).

  • Реєструє, що поточне обчислення (наприклад, рендер компонента) залежить від цієї властивості.

  • Vue зберігає залежності у WeakMap -> Map -> Set:

    javascript
    targetMap = WeakMap { target (об'єкт) -> Map { key (поле) -> Set(effect) } }
  1. Функція trigger()
  • Викликається при записі (set).
  • Знаходить усі ефекти (наприклад, функції рендера), які залежать від зміненого ключа.
  • Викликає їх повторно -> інтерфейс оновлюється.

Механізм у Vue 2 (Object.defineProperty)

У старій версії Vue не було Proxy, тому Vue перевизначав геттери і сеттери кожної властивості вручну:

javascript
Object.defineProperty(obj, 'count', { get() { Dep.depend() // підписуємо спостерігачів return value }, set(newVal) { value = newVal Dep.notify() // повідомляємо всіх спостерігачів } })

Але цей підхід мав обмеження:

  • не можна було відстежувати додавання нових властивостей (obj.newProp = ...)
  • не можна було відстежувати видалення властивостей
  • доводилося використовувати Vue.set() і Vue.delete()

Тому у Vue 3 перейшли на Proxy, який вирішує всі ці проблеми.


Підсумок

Версія VueМеханізм реактивностіЩо перехоплюєОбмеження
Vue 2Object.defineProperty()Тільки наявні властивостіНе бачить нові ключі, потребує Vue.set()
Vue 3ProxyБудь-які операції читання/запису, включно з новими властивостямиНемає обмежень, швидше і чистіше

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.