Vuex: state updates, but computed property doesn't

I have a component which takes a property called ‘endpoints’ from the store, adjusts it slightly…

computed: {
            ...mapState(['endpoints']),
			adjustedEndpoints () {
            	if (this.endpoints){
		            return this.endpoints.map(x => {
			            x.displayName = x.name;
			            return x;
		            })
                }
			},

…and passes it to a table component in the template:

    <b-table show-empty
             stacked="md"
             :items="adjustedEndpoints"
             :fields="fields"
             :current-page="currentPage"
             :per-page="perPage"
             :filter="filter"
             :sort-by.sync="sortBy"
             :sort-desc.sync="sortDesc"
             :sort-direction="sortDirection"
             @filtered="onFiltered"
    >

The issue is that when I edit an endpoint’s properties, I see it change in the Vue component state, but this is not reflected in the rendered component until reload. I am guessing that the adjustedEndpoints() function is not being called automatically.

How can I fix this?I have a component which takes a property called ‘endpoints’ from the store, adjusts it slightly…

computed: {
            ...mapState(['endpoints']),
			adjustedEndpoints () {
            	if (this.endpoints){
		            return this.endpoints.map(x => {
			            x.displayName = x.name;
			            return x;
		            })
                }
			},

…and passes it to a table component in the template:

    <b-table show-empty
             stacked="md"
             :items="adjustedEndpoints"
             :fields="fields"
             :current-page="currentPage"
             :per-page="perPage"
             :filter="filter"
             :sort-by.sync="sortBy"
             :sort-desc.sync="sortDesc"
             :sort-direction="sortDirection"
             @filtered="onFiltered"
    >

The issue is that when I edit an endpoint’s properties, I see it change in the Vue component state, but this is not reflected in the rendered component until reload. I am guessing that the adjustedEndpoints() function is not being called automatically.

Inside the store, here is my getter:

		endpoints: (state) => {
			return state.endpoints;
		}

…my action:

		updateEndpoint (context, endpoint) {
			return new Promise(resolve => {
				appService.updateEndpoint(endpoint)
					.then((data) => {
						context.commit('updateEndpoint', data);
						resolve();
					})
					.catch(() => console.log('error getting endpoints'));
			});
		},

…and my mutation:

		updateEndpoint (state, endpoint) {
			state.endpoints = state.endpoints.map(x => {
				if (x.id === endpoint.id)
					{
						endpoint.displayName = endpoint.name;
						return endpoint;
					}
				return x;
			});
		},

This depend on how you edit an endpoint’s properties if you edit a property that is not specified in the state at the load you have to use Vue.set functionality see:

If my first affirmation is wrong maybe add a adjustedEndpoints function directly to the vuex store ?

The issue is that you aren’t updated the Vuex state, simply the local component state. The computed property watches this.endpoints so on initial render it grabs the state, but because you never update the Vuex state it doesn’t cause the computed property to re-evaluate.

You need to update the Vuex state endpoints in order for adjustedEndpoints to evaluate again.

I am actually not directly changing the component state, but rather updating the Vuex state like this:

I use Axios to make a request to the backend. The backend returns an updated endpoint, which I then commit in a mutation, where I replace state.endpoints with a new copy:

{ state.endpoints = 
state.endpoints.map(x => { if (x.id === endpoint.id) return endpoint; return x; 
}); }

From that, I can see the component state change.

Vue.set doesn’t make a difference, unfortunately. I will try to do adjustedEndpoints directly from the store.

Can you show the part of your store ? Even better a code pen showing the problem ? Maybe you are not using Vue.set correctly.

You can also try in your mutation:

{ state.endpoints = Object.assign({}, 
state.endpoints.map(x => { if (x.id === endpoint.id) return endpoint; return x; 
})); }

I’ve updated the original post with the relevant methods from my store.

I am guessing that the adjustedEndpoints() function is not being called automatically.

have you actually verified that in the devtools? you can check to see if the computed property has updated or not …

Maybe your issue with with that <b-table> component?

Found the problem.

In my initial state in the Vuex store, I did not declare the ‘endpoints’ property.

That was the entire problem.

4 Likes

I just had a similar problem. My issue was that I did not setup default values in Vuex store.

1 Like

I got this error ones again. Another reason for it to happen is if by mistake setting values to an array where it should be an object.

I had something like this:

state.table.data = []; // Array
state.table.data['hello'] = 'world';

It outputted everything correctly in the console, but not in the template.

Correct in this case should be:

state.table.data = {}; // Object
state.table.data['hello'] = 'world';

That’s because in javascript key/value pairs can’t be used in arrays.

1 Like