There are two pages (or, components with respect to vue's terminology) who both needs same set of data, which is provided via an api over http. The order in which those two components would be visited is undefined (or, user-behavior-dependent) and the data should only be fetched once since it won't change alot.
I am aware of the idea that a state
stores the actual data, mutation
s mutate the state
, and action
s do the dirty works as async requests, multi-mutation coordinating, etc.
The question is: What is the best practice to do some caching logic as described above ?
I have come up with following three ways but none of them looks perfect to me:
Cons:
I need to dispatch the action before accessing the data at everywhere because I do not know if the data has already been fetched.
// ComponentA async mouted () { await this.store.dispatch('fetchData') this.someData = this.store.state.someData } // ComponentB async mouted () { await this.store.dispatch('fetchData') this.someData = this.store.state.someData } // vuex action { async fetchData ({ state, commit }) { // handles the cache logic here if (state.someData) return commit('setData', await apis.fetchData()) } }
Caching logic is scattered all over the code base -- smelly~
// ComponentA async mouted () { if (this.store.state.someData === undefined) { // handles the cache logic await this.store.dispatch('fetchData') } this.someData = this.store.state.someData } // ComponentB async mouted () { if (this.store.state.someData === undefined) { // handles the cache logic await this.store.dispatch('fetchData') } this.someData = this.store.state.someData } // vuex action { async fetchData ({ state, commit }) { commit('setData', await apis.fetchData()) } }
Maybe the most prefect-looking among these three, but I feel a little strange to use a return value of an action dispatch as data. And the caching logic would be scattered all over the actions as the store grows (there would be more and more actions repeating same caching logic)
// ComponentA async mouted () { this.someData = await this.store.dispatch('fetchData') } // ComponentB async mouted () { this.someData = await this.store.dispatch('fetchData') } // vuex action { async fetchData ({ state, commit }) { if (!state.someData) commit('setData', await apis.fetchData()) return state.someData } }
I perfer to put the caching logic into my 'vue&vuex-independent' network layer. But then the 'caching' part of the network layer may become another 'vuex' store. XD