Ответ
Потеря реактивности в Vue происходит, когда изменения данных не вызывают обновления интерфейса. Основные причины:
- Добавление новых свойств в объект:
data() {
return { user: { name: 'Alice' } }
}
// Не реактивно:
this.user.age = 25
// Реактивно:
this.$set(this.user, 'age', 25)
- Изменение длины массива:
// Не реактивно:
this.items.length = 0
// Реактивно:
this.items = []
- Индексы массива:
// Не реактивно:
this.items[0] = newValue
// Реактивно:
this.$set(this.items, 0, newValue)
Для объектов Vue использует Object.defineProperty (в Vue 2) или Proxy (в Vue 3), которые не отслеживают динамически добавляемые свойства. Все данные для реактивности должны быть объявлены изначально в data().
Ответ 18+ 🔞
Да ты посмотри, какой народ-то у нас пошёл! Сидит, значит, на Vue, а у него хуйня какая-то творится — данные поменял, а интерфейс нихрена не обновился, как будто в рот ему чих-пых! Ну, слушай, давай разбираться, где тут собака зарыта, а то ведь реально можно с ума сойти.
Первая причина, от которой у меня волосы дыбом встают — это когда ты новые свойства в объект пихаешь, как последний распиздяй. Смотри, объявил ты объект:
data() {
return { user: { name: 'Alice' } }
}
И думаешь: «О, сейчас я ему age добавлю, и всё будет пиздец как реактивно!»
// НЕ РЕАКТИВНО, БЛЯДЬ! ВОТ ТУТ-ТО ТЫ И ПОПАЛСЯ!
this.user.age = 25
А Vue смотрит на это и такой: «Мужик, ты чё, охренел? Я про это свойство нихуя не знаю, я его не отслеживаю!». И интерфейс стоит колом, как истукан. Надо делать по-человечески, через $set:
// А вот так — РЕАКТИВНО, красава! Vue теперь в курсе дела.
this.$set(this.user, 'age', 25)
Вторая история — длину массива менять. Ну, представим, ты решил массив обнулить, чтоб по-быстрому:
// НЕ РЕАКТИВНО! Это пиздец, какой тупой способ!
this.items.length = 0
Vue на это среагирует примерно так: «Ну и хуй с тобой». Массив-то пустой, а вот реактивность на такое изменение нихуя не сработает. Правильно — присвоить новый пустой массив:
// РЕАКТИВНО! Вот теперь Vue обновится, как миленький.
this.items = []
Третий номер нашей программы — попытка поменять элемент массива по индексу. О, это классика, ёпта!
// НЕ РЕАКТИВНО! Опять ты в лужу сел, дружок.
this.items[0] = newValue
Vue опять нихуя не увидит. Надо опять звать на помощь $set:
// РЕАКТИВНО! Теперь всё в ажуре.
this.$set(this.items, 0, newValue)
А знаешь, в чём корень всего этого зла, блядь? Внутри Vue 2 использует Object.defineProperty, а в третьей версии — Proxy. И эта штука, она как хитрая жопа — не отслеживает свойства, которые появились потом, из ниоткуда. Поэтому все данные, которые должны быть реактивными, надо объявлять сразу, в data(), как порядочные люди. Не объявил — потом не жалуйся, что у тебя всё ебётся и не работает.
Вот и весь сказ, блядь. Запомни эти три пункта, и жить станет проще, а интерфейс будет обновляться, а не висеть, как манда с ушами.