Search code examples
javascriptvue.jsvuex

Vuex Mutation running, but component not updating until manual commit in vue dev tools


I have a vue component that I can't get to update from a computed property that is populated from a service call.

Feed.vue

<template>
    <div class="animated fadeIn">
        <h1 v-if="!loading">Stats for {{ feed.name}}</h1>      
        <h2 v-if="loading">loading {{ feedID }}</h2> 
    </div>
</template>
<script>
    export default {
        data: () => {
            return {
                feedID: false
            }
        },
        computed: {
            feed(){
                return this.$store.state.feed.currentFeed
            },
            loading(){
                return this.$store.state.feed.status.loading;
            }
        },
        created: function(){    
            this.feedID = this.$route.params.id;
            var fid = this.$route.params.id;
            const { dispatch } = this.$store;
            dispatch('feed/getFeed', {fid});
        }
    }
</script>

That dispatches 'feed/getFeed' from the feed module...

feed.module.js

import { feedStatsService } from '../_services';
import { router } from '../_helpers';

export const feed = {
    namespaced: true,
    actions: {
        getFeed({ dispatch, commit }, { fid }) {
            commit('FeedRequest', {fid});
            feedStatsService.getFeed(fid)
                .then(
                    feed => {
                        commit('FeedSuccess', feed);
                    },
                    error => {
                        commit('FeedFailure', error);
                        dispatch('alert/error', error, { root: true });
                    }
                )
        }
    },
    mutations: {
        FeedRequest(state, feed) {
            state.status = {loading: true};
            state.currentFeed = feed;
        },
        FeedSuccess(state, feed) {
            state.currentFeed = feed;
            state.status = {loading: false};
        },
        FeedFailure(state) {
            state.status = {};
            state.feed = null;
        }
    }
}

The feedStatsService.getFeed calls the service, which just runs a fetch and returns the results. Then commit('FeedSuccess', feed) gets called, which runs the mutation, which sets state.currentFeed=feed, and sets state.status.loading to false.

I can tell that it's stored, because the object shows up in the Vue dev tools. state.feed.currentFeed is the result from the service. But, my component doesn't change to reflect that. And there is a payload under mutations in the dev tool as well. When manually commit feed/feedSuccess in the dev tools, my component updates.

What am I missing here?

Vue Dev tools


Solution

  • In the same way that component data properties need to be initialised, so too does your store's state. Vue cannot react to changes if it does not know about the initial data.

    You appear to be missing something like...

    state: {
      status: { loading: true },
      currentFeed: {}
    }
    

    Another option is to use Vue.set. See https://vuex.vuejs.org/guide/mutations.html#mutations-follow-vue-s-reactivity-rules...

    Since a Vuex store's state is made reactive by Vue, when we mutate the state, Vue components observing the state will update automatically. This also means Vuex mutations are subject to the same reactivity caveats when working with plain Vue