Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to cache data in vuex

I am trying to asynchronously load data into vuex that is static but is used by multiple routes.I only want to fetch the data once and only when a route that needs it is visited. This is what I'm currently doing but I'm not sure if this is the correct convention or if there is a better/more Vueish way.

// store.js

export default new Vuex.Store({
  state: {
    _myData: null,
  },
  getters: {
    myData: (state) => new Promise((resolve,reject) => {
      if(state._myData){
        resolve(state._myData);
      } else {
        axios.get('http://myData.com/')
        .then(myData => {
          state._myData = myData;
          resolve(state._myData);
        });
      }
    })
  }
});

// ProfilePage.vue

<template>
 <div>{{myData}}</div>
</template>

<script>
export default {
  data() {
    return {
      myData:null
    }
  },
  async created(){
   this.myData = await this.$store.getters.myData;
  }
}
</script>

// AboutPage.vue

<template>
 <div>{{myData}}</div>
</template>

<script>
export default {
  data() {
    return {
      myData:null
    }
  },
  async created(){
   this.myData = await this.$store.getters.myData;
  }
}
</script>
like image 700
als9xd Avatar asked Mar 09 '19 00:03

als9xd


Video Answer


2 Answers

There is a correct way to do what you want but it is not the way you are doing it. Vue is quite strict on "Do not mutate vuex store state outside mutation handlers."

This means you should only alter the store state through a mutation, then use your getter only to get the data. You should also use an action to commit the mutation. So for what you are trying to do you should try it like this.

// AnyPage.vue

<template>
 <div>{{myData}}</div>
</template>

<script>
export default {
  data() {
    return {
      myData:null
    }
  },
  async created(){
    if(this.$store.state._myData === null) {
      await this.$store.dispatch('getData')
    }
    this.myData = this.$store.getters.myData;
  }
}
</script>

then in your store:

// store.js

export default new Vuex.Store({
  state: {
    _myData: null,
  },
  getters: {
    myData: (state) => state._myData,
  }
  mutations: {
    SET_DATA(state, data) {
      state._myData = data
    }
  }
  actions: {
    getData({ context }){
        axios.get('http://myData.com/')
        .then(res => {
          context.commit('SET_DATA', res)
        })
      }
    }
  }
});

You should read up in the docs which covers it all pretty well.

like image 51
Andrew1325 Avatar answered Sep 26 '22 17:09

Andrew1325


Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call context.commit to commit a mutation, or access the state and getters via context.state and context.getters. https://vuex.vuejs.org/guide/actions.html

try this:

// AnyPage.vue

<template>
 <div>{{myData}}</div>
</template>

<script>
export default {
  computed: {
    myData () {
      return this.$store.state.myData
    }
  },
  mounted () {
    this.$store.dispatch('getData')
  }
}
</script>

in store file:

// store.js

export default new Vuex.Store({
  state: {
    myData: null,
  },
  mutations: {
    SET_DATA(state, data) {
      state.myData = data
    }
  }
  actions: {
    getData({ context }){
        if (context.state.myData === null) {
            axios.get('http://myData.com/')
            .then(res => {
                context.commit('SET_DATA', res)
            })
        }
      }
    }
  }
});
like image 34
Marcelo Gondim Avatar answered Sep 24 '22 17:09

Marcelo Gondim