I have a simple app with a common stack :
- A backend server (Rails)
- A frontend app (Vue)
- A database (PG)
The Vue app fetch data from the backend using an action of the Vuex store library as so :
// store/store.js
import Vue from 'vue';
import Vuex from 'vuex';
import * as MutationTypes from '@/store/mutation-types';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
investment: {},
},
mutations: {
[MutationTypes.SET_INVESTMENT_SHOW](state, investment) {
state.investment = investment;
},
},
actions: {
fetchInvestment({ commit }, id) {
InvestmentsApi.get(id).then((response) => {
commit(MutationTypes.SET_INVESTMENT_SHOW, response.data);
});
},
},
getters: {
participation: state =>
state.investment.included[0],
},
});
The action is called in the created lifecycle hook of my component as so :
// components/Investment.vue
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'Investment',
computed: {
...mapState(['investment']),
...mapGetters(['participation']),
},
created() {
this.fetchData(this.$route.params.id);
},
methods: mapActions({
fetchData: 'fetchInvestment',
}),
};
There is a problem in the code I've written above, I actually use the computed value 'participation' in my template like this :
<BaseTitleGroup
:subtitle="participation.attributes.name"
title="Investissements"
/>
And of course, because I use participation at the time the component renders itself, I get this error from the getter method :
Error in render: "TypeError: Cannot read property '0' of undefined"
found in
---> <InvestmentSummary> at src/views/InvestmentSummary.vue
<App> at src/App.vue
<Root>
I think there are several solutions to solve this problem and I'm wondering which one is best practice or if there is a better one.
- The first solution would be to put a v-if attribute in my template to prevent the element from rendering while waiting for the data
- Con : The rendering offset (the element starts rendering when the data is there) ?
- Con : I would have to do it for every single component of my app that deals with async data, intuitively I would prefer to deal with this somewhere else (maybe the store?).
- Render the element and put fake data in the store, like "Loading..."
- Con : The little glitch the user sees when loading his page is ugly, when the text switches from loading to the real text.
- Con : The empty version of my store would be painful to write and super big when my app scales
- Change the getter to return the initial empty data, and not the store
- Con : Getters get more complicated
- Con : What about data that do not need a getter (maybe they are directly accessible from the state)
- Something else ?
I'm looking for the best solution to deal with this pattern, even if it's one of the above, I'm just not sure which one would be the best. Thanks a lot for reading ! Also, I use vue framework but I think it is more of a general question about modern javascript framework handling of async data and rendering.
Sorry for the long post, here is a potato ! (Oops, not on 9gag ;) )