1
votes

I am building a simple movie app using Vue and Vuex and want to be able to add movies to a favourites list when a button is clicked. I am adding the movies to the store but I want the text on the button to change from 'Add to favourites' to 'Remove from favourites' when the movie has been added. I am using a computed property to read the Vuex store to determine the text on the button based on whether the movie is in the favourites list in the store or not. If I reload the page, the text on the button changes correctly but I am unable to get the text to change when just clicking on the button to add/remove movie. How can I get the computed properties to be re computed on a change in the Vuex store?

Here is my movie component:

<template>
  <div class="single-movie-page">
    <img class="movie-img" :src="movie.img"></img>
    <div class="single-movie-info">
      <h1>{{movie.title}}</h1>
      <h3>Rating: {{movie.stars}}</h3>
      <h3>Released Date: {{movie.releaseDate}}</h3>
      <p>{{movie.overview}}</p>
      <button v-on:click="addRemoveFavourites" >{{ favourite }}</button>
    </div>
  </div>
</template>

<script>
export default {
  props: ['movie'],
  computed: {
    favourite() {
      return this.$store.state.favourites[this.movie.id] === undefined
        ? 'Add to Favourites'
        : 'Remove from Favourites'
    }
  },
  methods: {
    addRemoveFavourites() {
      this.$store.commit('changeFavourites', this.movie)
    }
  }
}
</script>

And here is my Vuex store:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    favourites: {}
  },
  mutations: {
    changeFavourites: (state, movie) => {
      if (state.favourites[movie.id]) {
        delete state.favourites[movie.id]
      } else state.favourites[movie.id] = movie
    }
  }
})

I tried using this.$forceUpdate() in the addRemoveFavourites method, but this didn't work either.

1
Thanks this is what I was looking for. I also forgot to take into account the fact that changing what is inside an object doesn't change the object itself. I tried using Object.assign but this didn't work. I guess I have to use these built in Vue methods.Anna Collins

1 Answers

5
votes

Bert has the right answer, you can't normally add/remove properties from an object and have them be reactive in Vuejs.

You need to use Vue.set and Vue.delete if you want them to be reactive.

So your mutation should look like this:

mutations: {
  changeFavourites: (state, movie) => {
    if (state.favourites[movie.id]) {
      Vue.delete(state.favourites, movie.id)
    } else {
      Vue.set(state.favourites, movie.id, movie)
    }
  }
}