Дочерний компонент 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)"
>

Вот проект на Github

И живая демонстрация

Помощь приветствуется

3 ответа

Компонент не обновляется, потому что вложенные значения вашего prop не являются реактивными, поэтому vue не замечает, что они меняются.

Как сделать вложенные свойства реактивными во Vue

Следующее относится ко всему состоянию в вашем приложении vue - независимо от того, находится ли оно в магазине vuex, ваш data() вариант или внутри prop.

По умолчанию vue делает состояние реактивным, только если оно объявлено. Это означает, что динамически (во время выполнения) назначенное состояние не является реактивным (например,mounted() { this.bar = 'two' } не создаст реактивного свойства bar в вашем data()).

Если вы хотите динамически создавать реактивное состояние, вам нужно следовать двум правилам:

  1. Все свойства должны быть установлены с помощью Vue.set(rootObject, key, value) (например mounted() { this.$set(this, 'bar', 'two') } - this.$set() это псевдоним для Vue.set()). Об этом читайте здесь: Vue Doku

  2. Массивы необходимо заполнить собственными свойствами массива (Array.prototype.push(), так далее.). Установка элементов массива по индексу не сделает эти элементы реактивными. Примечание: Vue.set(rootArray, 1, value)тоже не сработает - так как устанавливает элемент по индексу. Подробнее об этом здесь: Vue Gotchas

При необходимости вы можете вызвать this.$ ForceUpdate() в родительском компоненте после выброса, что приведет к повторной визуализации.

Не уверен, что основная проблема заключается в том, почему ваш дочерний компонент не запускает обновление автоматически.

Ответ @MarcRo правильный, но я хочу добавить еще одно решение. Потому что:

Компонент не обновляется, потому что вложенные значения вашего реквизита не являются реактивными, поэтому vue не замечает их изменения.

, предполагая, что вы изменяете объект, передаваемый дочернему компоненту в качестве свойства, отправка глубокой копии решает проблему, поскольку изменяется весь объект, а не вложенное значение.

Вот способ создать глубокую копию объекта:

      JSON.parse(JSON.stringify(object))
Другие вопросы по тегам