Дочерний компонент Vue не обновляется при изменении свойств
Я обновляю опору "упражнения", которая отправляется компоненту "тренировки" во Vue. В дочернем компоненте я испускаю функцию для увеличения набора, в котором вы находитесь. Функция запускается в родительском компоненте (я получаю console.logs()), но дочерний компонент не перерисовывается.
Родитель:
<ExerciseListItem
v-for="(exercise) in exercises"
v-on:completeSet="completeSet"
v-on:selectExercise="selectExercise"
v-bind:exercise.sync="exercise"
v-bind:isActiveExercise="exercise.slug === activeExerciseSlug"
v-bind:key="exercise.slug"
/>
Методы:
methods: {
completeSet: function(slug) {
console.log("complete-set", slug);
const exercise = this.getExerciseBySlug(slug);
exercise.completedSets++;
if (exercise.completedSets === exercise.totalSets) {
this.completeExercise(slug);
}
},
completeExercise: function(slug) {
this.getExerciseBySlug(slug).isComplete = true;
console.log("COMPLETE-exercise", slug);
},
getExerciseBySlug: function(slug) {
return this.exercises.find(exercise => exercise.slug === slug);
},
selectExercise: function(selectedSlug) {
this.activeExerciseSlug = selectedSlug;
}
},
Дочерний шаблон
<li
v-bind:class="{ 'white-box': true, complete: exercise.isComplete }"
v-on:click="exercise.totalSets > 1 ? $emit('selectExercise', exercise.slug) : $emit('completeSet', exercise.slug)"
>
Помощь приветствуется
3 ответа
Компонент не обновляется, потому что вложенные значения вашего prop
не являются реактивными, поэтому vue не замечает, что они меняются.
Как сделать вложенные свойства реактивными во Vue
Следующее относится ко всему состоянию в вашем приложении vue - независимо от того, находится ли оно в магазине vuex, ваш data()
вариант или внутри prop
.
По умолчанию vue делает состояние реактивным, только если оно объявлено. Это означает, что динамически (во время выполнения) назначенное состояние не является реактивным (например,mounted() { this.bar = 'two' }
не создаст реактивного свойства bar
в вашем data()
).
Если вы хотите динамически создавать реактивное состояние, вам нужно следовать двум правилам:
Все свойства должны быть установлены с помощью
Vue.set(rootObject, key, value)
(напримерmounted() { this.$set(this, 'bar', 'two') }
-this.$set()
это псевдоним дляVue.set()
). Об этом читайте здесь: Vue DokuМассивы необходимо заполнить собственными свойствами массива (
Array.prototype.push()
, так далее.). Установка элементов массива по индексу не сделает эти элементы реактивными. Примечание:Vue.set(rootArray, 1, value)
тоже не сработает - так как устанавливает элемент по индексу. Подробнее об этом здесь: Vue Gotchas
При необходимости вы можете вызвать this.$ ForceUpdate() в родительском компоненте после выброса, что приведет к повторной визуализации.
Не уверен, что основная проблема заключается в том, почему ваш дочерний компонент не запускает обновление автоматически.
Ответ @MarcRo правильный, но я хочу добавить еще одно решение. Потому что:
Компонент не обновляется, потому что вложенные значения вашего реквизита не являются реактивными, поэтому vue не замечает их изменения.
, предполагая, что вы изменяете объект, передаваемый дочернему компоненту в качестве свойства, отправка глубокой копии решает проблему, поскольку изменяется весь объект, а не вложенное значение.
Вот способ создать глубокую копию объекта:
JSON.parse(JSON.stringify(object))