0
votes

I have a getter in the vuex store which returns an array list from store state. I am updating the store state through mutation in an action called from the component even though the store getter is updated the mapped getter which is in the component is not updated with the latest data.

package versions

"vue": "2.6.11", "vuex": "^3.0.1"

index.js

import Vue from 'Vue'
import Vuex from 'vuex'
import '@styles/contact-list.scss'
import List from '@components/contactList'
import store from '@store'
Vue.use(EventBusPlugin)
Vue.use(Vuex)
let url = '/api/contacts'
let vueInstance = new Vue({
  el: '#contactContainer',
  components: { List },
  template: '<List/>',
  render (h) {
    return h(List, { props: { url: this.url, filter: this.filter, type: 'internal' } })
  },
  data () {
    return {
      url: url,
      filter: true
    }
  },
  store
}) 

Component

<template>
  <div>
    <div class="d-flex flex-row align-content-start flex-wrap">
      <contact-card
        v-for="(data) in displayList"
        :data="data"
        :key="data.unique_id"
      ></contact-card>
    </div>
  </div>
</template>

<script> 
 
import { mapActions, mapGetters, mapMutations } from 'vuex'
export default {
  name: 'ContactList',
  components: { 
    ContactCard 
  },
  props: {
    url: {
      required: true,
      type: String
    },
    filter: {
      type: Boolean,
      default: false
    },
    pageSize: {
      type: Number,
      default: 200
    },
    type: {
      type: String,
      default: 'external'
    }
  },
  computed: {
    ...mapGetters('contacts', ['displayList']),
    dataUrl () {
      return `${this.url}?type=${this.type}`
    }
  },
  mounted () {
    this.setType(this.type)
    this.loadData() 
  },
  data () {
    return {
      searchKey: '',
      sequence: 0
    }
  }, 
  methods: {
    ...mapActions('contacts', ['loadContacts', 'updateStatus']),
    ...mapMutations('contacts', ['setType']), 
    loadData () {
      this.loadContacts({ url: this.url })
    }
  }
}
</script>

Store

import Vue from 'vue'
import Vuex from 'vuex'
import contacts from './modules/contacts'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    contacts
  }
})

export default store

./modules/contacts


export default {
  namespaced: true,
  state : {
    type: 'external',
    externalList: [],
    internalList: []
  },
  mutations:{
    setContactList (state, list) {
      state.type === 'external' ? state.externalList = list : state.internalList = list
    },
    setType (state, type) {
      state.type = type
    }
  },
  getters:{
    displayList (state) {
      if (state.type === 'external') {
        return state.externalList
      } else {
        return state.internalList
      }
    }
  },
  actions:{
    loadContacts ({ commit, state }, payload) {
      const { url } = payload
      $.ajax({
        type: 'POST',
        url: url,
        data: {},
        contentType: 'application/json',
        success: (data) => {
          commit('setContactList', data)
        },
        error: (jqXHR, textStatus, errorThrown) => {
        }
      })
    }
  }
}

In the above code though I can see in developer tool vuex store getter is updated but it does not reflected in the mapped getter in the component. Can anyone help here what is wrong here thanks?

2

2 Answers

0
votes

There must be something else going on because it works as expected.

Below is almost same code (changes only to make it work from CDN and not require API)

Only strange thing I noticed was you have both template and render function on your root instance...but it works as If render function is present in the Vue option, the template will be ignored. Docs

Vue.use(Vuex)

const contacts = {
  namespaced: true,
  state : {
    type: 'external',
    externalList: [1, 2, 3],
    internalList: [4, 5, 6]
  },
  mutations:{
    setContactList (state, list) {
      state.type === 'external' ? state.externalList = list : state.internalList = list
    },
    setType (state, type) {
      state.type = type
    }
  },
  getters:{
    displayList (state) {
      if (state.type === 'external') {
        return state.externalList
      } else {
        return state.internalList
      }
    }
  },
  actions:{
    loadContacts ({ commit, state }, payload) {
      // to simulate Ajax loading...
      setTimeout(() => (commit('setContactList', [7, 8, 9])), 1500)
    }
  }
}

const store = new Vuex.Store({
  modules: {
    contacts
  }
})

const list = Vue.component('List', {
  props: {
    url: {
      required: true,
      type: String
    },
    filter: {
      type: Boolean,
      default: false
    },
    pageSize: {
      type: Number,
      default: 200
    },
    type: {
      type: String,
      default: 'external'
    }
  },
  template: `
    <div>
      <div v-for="(data) in displayList"> {{ data }}</div>
    </div>
  `,
  computed: {
    ...Vuex.mapGetters('contacts', ['displayList']),
  },
  mounted () {
    this.setType(this.type)
    this.loadData() 
  },
  methods: {
    ...Vuex.mapActions('contacts', ['loadContacts', 'updateStatus']),
    ...Vuex.mapMutations('contacts', ['setType']), 
    loadData () {
      this.loadContacts()
    }
  }
})

const app = new Vue({
  store,
  components: { list },
  template: `<List :url="url" />`,
  render (h) {
    return h('List', { props: { url: this.url, filter: this.filter, type: 'internal' } })
  },
  data () {
    return {
      url: "some url",
      filter: true
    }
  },
})
app.$mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.5.1/vuex.min.js"></script>

<div id="app"> </div>
-1
votes

your state should contains keys (ADDED BY YOUR HANDS) you wanna to be synchronized. Basically you should write your actual structure of all keys you wanna to be synchronized.

for example keys (added by you) = "reactivity" is working:

state:{
    externalList: null, // <--- added by you
    internalList: null  // <--- added by you
}

for example "reactivity" is NOT working:

state: {} // <--- externalList/internalList NOT added by you

in mutation

...
state.externalList = "hello"; // <--- not synchronized
...