Потеря реактивности и частые ошибки
↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая
Зачем это на собесе
«Почему компонент не обновляется?» — ждут перечня типовых причин.
Объяснение
| Ситуация | Почему теряется | Решение |
|---|---|---|
Деструктуризация reactive: const { a } = state | получаем примитив | toRefs(state) / toRef |
| Деструктуризация props (до 3.5) | то же | toRefs(props) или () => props.x; в 3.5 — реактивная деструктуризация |
Замена всего reactive: state = {...} | переменная указывает на другой объект | Object.assign(state, next) или ref |
Передача значения ref.value в composable | копия | передавать ref или геттер (toValue) |
ref внутри обычного объекта | не разворачивается | .value или reactive |
| Вынос реактивного в обычную переменную/класс | вне отслеживания | оставлять в реактивной структуре |
watch(state.prop) | не реактивный источник | watch(() => state.prop) |
markRaw/toRaw | намеренно отключено | использовать сознательно |
| Изменение вне Vue (сторонняя библиотека) | Vue не знает | triggerRef, копия/замена |
ref в Map/Set | ограниченно | использовать реактивные коллекции |
Асинхронность после await в watchEffect | зависимости не собираются | читать до await |
// Ошибка
const { count } = useCounter(); // count — число, если composable вернул reactive-объект
// Правильно: composable возвращает refs
function useCounter() { const count = ref(0); return { count, inc: () => count.value++ }; }
// Приём: принимать ref/геттер/значение
function useTitle(source: MaybeRefOrGetter<string>) { watchEffect(() => (document.title = toValue(source))); }Другие типовые ошибки:
- Мутация props (
props.x = 1) — предупреждение; эмитить событие или использоватьdefineModel. - Отсутствие
keyв списках. - Тяжёлые вычисления в шаблоне, а не в
computed. - Забытая очистка таймеров/слушателей.
- Обращение к DOM до
onMountedи безnextTickпосле изменения данных. - Реактивный объект с тяжёлыми не-реактивными данными (карты, инстансы) —
markRaw.
Нюансы и подводные камни
- Проверяйте
isRef,isReactive, Vue DevTools (подсветка обновлений). - Разворачивание
refв шаблоне работает только для верхнего уровня. - Реактивность массива: методы
push/spliceи индексная запись работают во Vue 3.
Практика
- Воспроизведите 5 случаев потери реактивности и исправьте.
- Перепишите composable, принимающий
MaybeRefOrGetter. - Найдите мутацию props в своём проекте.
Вопросы с ответами
Почему после деструктуризации
reactiveкомпонент не обновляется?Мы получаем копию значения, отвязанную от прокси; нужны
toRefs/toRef.
Как передать реактивное значение в composable?
Как
ref, геттер илиMaybeRefOrGetterи читать черезtoValue.