Как работает реактивность во Vue.js?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
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;
}
};