0
votes

I'm trying to use vuex as a layer between firestore and my vue application. My vuex store looks like this:

const store = new Vuex.Store({
    state: {
        posts: [],
    },

    mutations: {
        add_post(state, post) {
            state.posts[post.id] = post;
        },
    },

    actions: {
        async load_post(context, id) {
            let post = await db
                .collection('posts')
                .where('post_id', '==', id)
                .get();
            post = post.docs[0]; 

            post = {id, ...post.data()};
            context.commit('add_post', post);
        },
    }
});

And inside my Vue component:

export default {
    name: 'Post',
    beforeMount() {
        const id = this.$route.params.id;
        this.$store.dispatch('load_post', id);
    },
    data() {
        return {
            id: this.$route.params.id
        };
    },
    computed: {
        content() {
            return this.$store.state.posts[this.id];
        }
    }
};

Now, when navigating the website, the code seems to run fine. However, if I refresh the page then the content property becomes undefined. After some debugging, I've come to the conclusion that it tries to read from the store while loading(therefore being undefined), but when the store is ready nothing updates. So far I've tried watchers, vuex's mapState, nothing seems to work... any suggestions?

2
Vue computed properties are synchronous, so they will execute whether or not the store's state is ready. A more reliable approach would be to use a getter in your store that returns the state, and use a mapGetter call in your component.Len Joseph
I have tried using getters, and the result seems to be the same.Nlsnightmare
I think the issue could be that after the first time you load in state, when you refresh the page you are writing over it, and trying to mutate immutable data. Are you getting any errors in the console?Len Joseph
nope, 0 errors or warningsNlsnightmare
Interesting. My last suggestion would be to change the beforeMount to created, and change computed to beforeMount. That will at least ensure the correct sequence of calls.Len Joseph

2 Answers

0
votes

It's Vue reactivity problem. You should modify state.posts in vuex to make component reactive. Mutate state.posts[post.id] only will not make component reactive, because state.posts still point to old reference.

mutations: {
  add_post(state, post) {
      state.posts = {
        ...state.posts,
        [post.id]: post
      }
  },
},

or you can use JSON.parse(JSON.stringify())

add_post(state, post) {
  state.posts[post.id] = post;
  state.posts = JSON.parse(JSON.stringify(state.posts))
},
0
votes

Vue cannot detect a change on a nested property, which is not set in state on load. Try changing your mutation to this:

add_post(state, post) {
   Vue.set(state.posts, post.id, post);
}

// You need to import Vue at the top of your store file, when using the Vue.set() method
import Vue from 'vue';