Как устроена реактивность во Vue 3?
SeniorVue.js #vue #reactivity
Вопрос
Как работает система реактивности во Vue 3 изнутри?
Короткий ответ
Vue 3 оборачивает объекты в Proxy, который перехватывает чтение и запись свойств. При чтении свойства во время рендера Vue запоминает "кто на него подписан", а при записи — уведомляет всех подписчиков перерендериться.
Подробный ответ
Два ключевых примитива:
reactive(obj)— оборачивает объект вProxy. Перехватчикиget/setреализуют отслеживание (track) и уведомление (trigger) зависимостей. Работает только с объектами/массивами.ref(value)— обёртка с единственным свойством.value. Нужна для примитивов (number,string), которые нельзя проксировать напрямую. Внутриrefтоже используетProxy-подобный геттер/сеттер через объект-обёртку.
Механизм зависимостей:
- Во время выполнения "эффекта" (например, функции рендера компонента или
computed) Vue устанавливает текущий активный эффект. - При чтении реактивного свойства сеттер/геттер Proxy регистрирует этот эффект как зависимость свойства (
track). - При записи в свойство Vue находит все зависимые эффекты и запускает их заново (
trigger) — это и есть точечное обновление, без сравнения виртуального DOM целиком по всему дереву, как в React.
В шаблонах ref автоматически "разворачивается" (unwrap), поэтому пишут count, а не count.value — это делает компилятор шаблонов.
Пример
import { reactive, effect } from 'vue'
const state = reactive({ count: 0 })
effect(() => {
console.log('Текущее значение:', state.count) // подписка на state.count
})
state.count++ // эффект выше выполнится заново автоматически
Дополнительные вопросы
- Почему
reactiveне работает с примитивами, аref— работает? - Что произойдёт при деструктуризации
reactive-объекта и как это исправить (toRefs)? - Чем реактивность на
Proxy(Vue 3) отличается отObject.defineProperty(Vue 2)?