Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 535
mad Avatar asked Oct 18 '18 01:10

mad


People also ask

How do I update my Vuex data?

To create new data, you can use the insert , create , and new methods. They all insert new records to the Vuex Store but behave in a slightly different manner. The insert method will simply insert new records. You should pass an object containing records in data key to the method.

Can I call action from mutation Vuex?

In Vuex, actions are functions that call mutations. Actions exist because mutations must be synchronous, whereas actions can be asynchronous. You can define actions by passing a POJO as the actions property to the Vuex store constructor as shown below. To "call" an action, you should use the Store#dispatch() function.

What is the difference between Vuex mutations and actions?

Mutations are intended to receive input only via their payload and to not produce side effects elsewhere. While actions get a full context to work with, mutations only have the state and the payload .

Is Vuex commit synchronous?

In Vuex, mutations are synchronous transactions: store. commit('increment') // any state change that the "increment" mutation may cause // should be done at this moment.


2 Answers

Hey for all the people coming to this and not being able to find a solution. The following was what worked for me:

Declaring base state:

state: {
  mainNavData: [],
}

Then I had my action which is calling the now fixed mutation:

actions : {
  async fetchMainNavData({ commit }) {
    var response = await axios.get();
    commit('setMainNavData', response));
  },
  
};

Now my mutation is calling this updateState() function which is key to it all

mutations = {
  setMainNavData(state, navData) {
    updateState(state, 'mainNavData', navData);
  },
};

This is what the updateState function is doing which solved my issues.

const updateState = (state, key, value) => {
  const newState = state;
  newState[key] = value;
};

After adding updateState() my data reactively showed up in the frontend and I didn't have to manually commit the data in Vue tools anymore.

please note my store is in a different file, so its a little bit different.

Hope this helps others!

like image 113
Sweet Chilly Philly Avatar answered Nov 11 '22 20:11

Sweet Chilly Philly


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

like image 44
Phil Avatar answered Nov 11 '22 20:11

Phil