Как работает реактивность во Vue.js?
Sobes Copilot
Get answers in real time
Answer from AI
sobes.tech AI
Реактивность во Vue.js основана на системе отслеживания зависимостей property.
При создании экземпляра Vue, данные в data преобразуются в реактивные. Для примитивов (string, number, boolean) используется Object.defineProperty (во Vue 2) или Proxy (во Vue 3) для перехвата операций get и set. Для объектов и массивов также применяется обход свойств и замена методов массива, чтобы они уведомляли об изменениях.
Когда свойство читается в template или computed property, создается зависимость. Внутренний механизм Vue (Watcher) запоминает, какой watcher зависит от данного свойства.
При изменении реактивного свойства, его сеттер уведомляет всех зависимых watcher'ов. Watcher'ы, в свою очередь, запускают пересчет computed properties или перерисовку компонентов.
Во Vue 3 используется Proxy API, что обеспечивает более полную реактивность, включая добавление, удаление и изменение элементов массива по индексу.
Ключевые компоненты:
- Observer/Reactive Proxy: Преобразует данные в реактивные, отслеживая get и set.
- Dep (Dependency): Класс, который собирает watcher'ы, зависящие от конкретного свойства.
- Watcher: Сущность, которая следит за изменением свойства и запускает действие (пересчет или перерисовка).
Пример работы во Vue 2 с Object.defineProperty:
// Внутренний механизм Vue
function defineReactive(obj, key, val) {
// Создаем объект Dep для данного свойства
const dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
// Если есть активный Watcher, добавляем его в Dep
if (Dep.target) {
dep.depend(); // Добавляем зависимость Watcher -> Dep
}
return val;
},
set: function reactiveSetter(newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify(); // Уведомляем все зависимые Watcher'ы
}
});
}
Пример работы во Vue 3 с Proxy:
// Внутренний механизм Vue с использованием Proxy
function createReactiveObject(target) {
return new Proxy(target, reactiveHandlers); // reactiveHandlers содержат логику get/set
}
const reactiveHandlers = {
get(target, key, receiver) {
track(target, 'get', key); // Отслеживаем чтение свойства
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, 'set', key, value); // Запускаем обновление
return result;
}
};