I'm updating an 'exercise' prop that gets sent to a 'workout' component in Vue. In the child component, I'm emitting a function to increment the set you're on. The function is firing in the parent component (I'm getting console.logs()), but the child component isn't re-rendering.
<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)"
>
Here's the project on Github
And a live demo
Help appreciated 😊
The component is not updating because the nested values of your prop
are not reactive, hence, vue does not notice they are changing.
The following applies to all state in your vue app - no matter whether it is located in a vuex store, your data()
option, or inside a prop
.
By default, vue only makes state reactive if it is declared. That means dynamically (at runtime) assigned state is not reactive (e.g. mounted() { this.bar = 'two' }
will not create a reactive property bar
in your data()
).
All properties need to be set with Vue.set(rootObject, key, value)
(e.g. mounted() { this.$set(this, 'bar', 'two') }
- this.$set()
is an alias for Vue.set()
). Read about it here: Vue Doku
Arrays need to be filled with native array properties (Array.prototype.push()
, etc.). Setting array elements by index will not make these elements reactive. Note: Vue.set(rootArray, 1, value)
also will not work - as it sets the element by index. Read more about it here: Vue Gotchas
If needed you can call this.$forceUpdate() in the parent component after the emit, which will force a re-render.
Not sure the underlying problem on why your child component is not triggering the update automatically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With