Реактивность: ref, reactive, shallowRef, toRef, toRefs
↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая
Зачем это на собесе
Ядро Vue: как работает реактивность, когда
ref, когдаreactive, что такое.value.
Объяснение
Реактивность Vue 3 основана на Proxy: чтение внутри эффекта регистрирует зависимость (track), запись уведомляет подписчиков (trigger).
import { ref, reactive, toRef, toRefs, shallowRef, shallowReactive, readonly, isRef, unref, toRaw, triggerRef } from "vue";
const count = ref(0); // count.value
count.value++;
const user = reactive({ name: "A", address: { city: "M" } }); // прокси объекта, без .value
user.address.city = "SPb"; // глубокая реактивность
const state = reactive({ a: 1, b: 2 });
const a = toRef(state, "a"); // ref, связанный с полем (реактивность сохраняется)
const { a: a2, b } = toRefs(state); // все поля как refs — безопасная деструктуризация
const big = shallowRef(hugeObject); // реактивно только .value = ...; внутренности не отслеживаются
big.value = { ...big.value }; // замена триггерит; мутация — нет (triggerRef(big))
const ro = readonly(state);| API | Назначение |
|---|---|
ref(x) | контейнер для значения любого типа, .value |
reactive(obj) | глубокий реактивный прокси объекта (не примитивы) |
shallowRef/shallowReactive | только верхний уровень (производительность больших структур) |
toRef/toRefs | связь с полями реактивного объекта |
readonly | защита от записи |
toRaw, markRaw | доступ к исходному объекту / отключение реактивности |
isRef, unref, toValue | вспомогательные |
customRef | своя логика (debounce ref) |
ref vs reactive: рекомендуется ref по умолчанию — работает с примитивами, можно заменить значение целиком, нет потери реактивности при передаче; reactive удобен для локального объекта состояния, но теряется при деструктуризации и замене всей ссылки.
В шаблоне ref верхнего уровня разворачивается автоматически ({{ count }}); внутри вложенных объектов — только если ref лежит в reactive.
Нюансы и подводные камни
refвнутри обычного объекта (не reactive) не разворачивается: нужен.value.reactiveнельзя полностью заменить:state = {...}теряет реактивность (используйтеObject.assignилиref).- Прокси не идентичен исходному объекту:
state !== toRaw(state). - Большие неизменяемые структуры (карты, графики, экземпляры классов) —
shallowRef/markRaw. - Реактивность работает только для объектов, созданных до чтения; добавление новых свойств отслеживается (в отличие от Vue 2).
Практика
- Сравните поведение
ref/reactiveпри деструктуризации и замене. - Оберните большую структуру в
shallowRefи обновляйте заменой. - Реализуйте
debouncedRefчерезcustomRef.
Вопросы с ответами
Чем
refотличается отreactive?
ref— контейнер значения с.value(любые типы),reactive— прокси объекта без.value, но с ограничениями (нельзя примитивы, теряется при замене).
Зачем
toRefs?Чтобы деструктурировать реактивный объект без потери реактивности.
Когда
shallowRef?Для больших структур, где нужна реактивность только при замене всего значения.