Як 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"Що відбувається крок за кроком:
- Створення 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
}
})- Функція
track()
-
Викликається при читанні властивості (
get). -
Реєструє, що поточне обчислення (наприклад, рендер компонента) залежить від цієї властивості.
-
Vue зберігає залежності у WeakMap -> Map -> Set:
javascripttargetMap = WeakMap { target (об'єкт) -> Map { key (поле) -> Set(effect) } }
- Функція
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 2 | Object.defineProperty() | Тільки наявні властивості | Не бачить нові ключі, потребує Vue.set() |
| Vue 3 | Proxy | Будь-які операції читання/запису, включно з новими властивостями | Немає обмежень, швидше і чистіше |
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.