Що робить `reactive()` у Vue 3?
1. Що робить reactive()
Функція reactive() приймає звичайний об'єкт і повертає його реактивну (проксійовану) версію.
import { reactive } from 'vue'
const state = reactive({
count: 0,
user: { name: 'Tim' }
})Тепер, коли ти зміниш будь-яку властивість об'єкта:
state.count++
state.user.name = 'Alex'Vue автоматично відстежить ці зміни та оновить усі ефекти, обчислення чи компоненти, які від них залежать.
2. Як це працює під капотом
Під капотом reactive() створює Proxy-обгортку над переданим об'єктом.
Спрощено:
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
// при зчитуванні значення реєструємо залежність
track(target, key)
const res = Reflect.get(target, key, receiver)
// якщо значення - об'єкт, робимо його реактивним рекурсивно
if (typeof res === 'object' && res !== null) {
return reactive(res)
}
return res
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
// якщо значення справді змінилося - тригеримо оновлення
if (oldValue !== value) {
trigger(target, key)
}
return result
}
})
}track() - запам'ятовує, що поточне обчислення (effect/render) залежить від цієї властивості.
trigger() - оповіщає всі ефекти, що властивість змінилася.
3. Приклад «у дії»
import { reactive, effect } from 'vue'
const state = reactive({ count: 0 })
effect(() => {
console.log(`Кількість: ${state.count}`)
})
state.count++ // "Кількість: 1"- При першому виклику
effect()Vue зчитуєstate.count-> викликаєtrack(). - Vue "запам'ятовує": ця функція залежить від
state.count. - Коли
state.countзмінюється ->trigger()запускаєeffect()знову. - Консоль друкує нове значення.
4. Що робить reactive() внутрішньо
| Етап | Що робить Vue |
|---|---|
| 1. Приймає об'єкт | Перевіряє, чи він уже не є реактивним |
| 2. Створює Proxy | Перехоплює get і set |
3. При get -> track() | Реєструє залежність |
4. При set -> trigger() | Повідомляє всі залежні ефекти |
| 5. Повертає обгортку | Яка поводиться як вихідний об'єкт, але «реагує» на зміни |
5. Відмінність від ref()
| Характеристика | reactive() | ref() |
|---|---|---|
| Тип даних | Обгортає об'єкт | Обгортає примітив (число, рядок тощо) |
| Звернення | Прямий доступ (state.count) | Потрібен .value (count.value) |
| Вкладені об'єкти | Автоматично стають реактивними | Потрібно обгортати вручну |
| Коли використовувати | Для складних станів | Для простих значень |
Приклад:
const state = reactive({ count: 0 })
const count = ref(0)
state.count++ // реактивно
count.value++ // реактивно6. Важливі особливості
reactive()працює лише з об'єктами Якщо передати примітив (число, рядок тощо), Vue просто поверне його як є:
reactive(10) // поверне 10, не реактивно- Реактивність поширюється ліниво (deep reactive) Вкладені об'єкти стають реактивними лише при першому зверненні до них.
- Порівняння за посиланням
Оскільки це Proxy,
state !== rawObject:
const raw = { x: 1 }
const proxy = reactive(raw)
console.log(proxy === raw) // false- Можна отримати оригінал за допомогою
toRaw():
import { toRaw } from 'vue'
const original = toRaw(state)- Можна «заморозити» об'єкт від реактивності за допомогою
markRaw():
import { markRaw } from 'vue'
const nonReactive = markRaw({ foo: 'bar' })7. Коли використовувати reactive()
-
Для об'єктів стану компонентів:
javascriptconst form = reactive({ name: '', email: '', accepted: false }) -
Для складних структур (вкладені об'єкти, масиви, колекції):
javascriptconst data = reactive({ users: [{ id: 1 }, { id: 2 }], meta: { total: 2 } }) -
Для централізованих сховищ стану (наприклад, без Vuex / Pinia):
javascriptexport const store = reactive({ user: null, isAuth: false })
8. Підсумок
reactive()робить звичайний об'єкт реактивним за допомогою Proxy. Vue автоматично відстежує всі читання й записи його властивостей. Будь-які ефекти, шаблони чи обчислення, що залежать від цих властивостей, автоматично оновлюються при зміні даних.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.