Search code examples
javascriptvue.jsvuex

Update prop property when vuex store changes


After a successful mutation to the vuex store (state.posts.post.comments) using this code, and using Vue.set so Vue can recognize the addition of an object property:

store/modules/post.js

const mutations = {
    [types.SET_POST_COMMENTS] (state, { comments, id }) {
      let post = state.posts.find(post => post._id === id)
      Vue.set(post, 'comments', comments)
    }
}

There is no update to the template or component. The prop post is non-reactive (I assume because even the watcher isn't triggered). I've double checked and the Vuex store for each post's comments property is successfully being updated with a comments object, but the component SinglePost.vue doesn't see these changes.

SinglePost.vue

export default {
  name: 'single-post',
  props: {
    'post': {
      type: Object
    }
  },
  data () {
    return {
      currPost: this.post // tried to reassign post locally
    }
  },
  computed: {
    comments() {
      return this.post.comments // tried to compute comments locally
    }
  },
  watch: {
    post: function(val) { // tried to watch currPost for changes
       console.log('never triggered')
       this.currPost = val 
    }
  }

Ultimately, I can just set a local var by explicitly returning comments from the store to a component method and setting a local comments object, but I want to use my central store (and assume there'd be a way).

SinglePost template

{{comments}} // always empty
{{post}} // doesn't reflect store Vue.set for post.comments
{{currPost}} // doesn't reflect store Vue.set for post.comments

Edit

How I'm getting posts is:

getPosts ({ commit, state, getters, dispatch, rootState }, ctx) {
  //other stuff
  APIHelper.post('/post/search', mergedPayload).then(res => {
    var results = res.data.results
    commit('SET_POSTS', posts || [])
    // where SET_POSTS is just state.posts = posts

the vuex action getPosts is called from Posts.vue component without returning anything since it's set by a mutation @click="getPosts(this.context)" (this works great for setting the posts)

    <div v-for="post in posts">
      <single-post :key="post._id" :post="post" context="feed" />
    </div>

Solution

  • You should use vuex's mapGetters helper method.

    computed: {
        ...mapGetters({
            currPost: 'GET_CURRENT_POST'
        })
    },
    

    It gives access to store state and is reactive so you won't need watchers or additional computeds.