1
votes

When a computed value changes, my PreviewExerciseItem is not getting rerendered. The computed value is a getter from my vuex store.

I don't mutate my vuex state, I set a new Object. This is my mutation:

selectedWorkout: (state, workout) => {
  state.selectedWorkout = {...workout};
}

Getter: selectedWorkout: (state) => state.selectedWorkout,

Here is my component. The PreviewExerciseItem component is not rerendered when my selectedWorkout changes but the h1 about is getting updated properly

<template>
    <div v-if="selectedWorkout">
        <h1 v-if="selectedWorkout">{{selectedWorkout.exercises[1].progression}}</h1>
        <PreviewExerciseItem v-for="(exercise, index) in selectedWorkout.exercises" :key="exercise.presetKey" 
            :exercise="exercise" :index="index" :selected="selectedExercise === index"
            v-on:click.native="selectedExercise = index"/>

    </div>
</template>

<script>

import db from '@/api/db'
import { mapGetters, mapActions, mapState } from "vuex";
import PreviewExerciseItem from "@/components/PreviewExerciseItem.vue"


export default {
    components: {
        PreviewExerciseItem
    },
    async asyncData({ store, params }) {
        await store.dispatch('selectedRoutine', params.id);
        return { routineId: params.id }
    },
    computed: {
        ...mapGetters(['user', 'selectedRoutine', 'selectedWorkout']),
    },
    watch: {
        user: async function (user) {
            const status = await db.fetchRoutineStatus(user.uid, this.routineId);
            this.$store.dispatch('selectedWorkout', status);
            console.log('Workout1', this.selectedWorkout) // Logs correctly updated Object
        },
        selectedWorkout: function (selectedWorkout) {
            this.workout = {...selectedWorkout};
            console.log('Workout2', this.selectedWorkout) // Also updated object
            this.$forceUpdate();    // Not doing anything
        }
    },
}
</script>

EDIT: The problem is probably with my mutation. When I use state.selectedWorkout = JSON.parse(JSON.stringify(workout)); instead of state.selectedWorkout = {...workout}; it works. I thought state.selectedWorkout = {...workout}; would assign a new Object but it seems like it doesn't. I don't really like the JSON solution, is there a better way to assign a new Objet? I also tried state.selectedWorkout = Object.assign({}, workout) which isn't working either.

1
Object.assign and {...} don't work because it breaks reference only on first level, if you have nested an object or an array inside it would not break reference to them. So I geuss you have nested an object/arrays. Deepclone fix that issue because it breaks reference on every nesting level - Piotr BiaƂek

1 Answers

0
votes

You need to use this form JSON.parse(JSON.stringify(workout)); to deep clone the workout object.

Deep Clone