Committing a Vuex mutation after an asynchronous operation does not trigger state update

I've come across several similar inquiries regarding this issue in various forums, yet I am unable to find a solution.

In my form, I'm using mapGetters to update input values based on the Vuex state:

    ...mapGetters({
      show: "getShow"
    }),

Here is an example of a form input (using Bootstrap Vue):

      <b-form-input
        id="runtime"
        name="runtime"
        type="text"
        size="sm"
        v-model="show.runtime"
        placeholder="Runtime"
      ></b-form-input>

The form component includes the following method:

    async searchOnDB() {
      var showId = this.show.showId;
      if (!showId) {
        alert("Please enter a showId");
        return;
      }
      try {
        await this.$store.dispatch("searchShowOnDB", showId);
      } catch (ex) {
        console.log(ex);
        alert("error searching on DB");
      }
    },

and this action on the store:

    async searchShowOnDB({ commit, rootState }, showId) {
      var response = await SearchAPI.searchShowOnDB(showId);
      var show = {
        show_start: response.data.data.first_aired,
        runtime: response.data.data.runtime,
        description: response.data.data.overview
      };
      var new_show = Object.assign(rootState.shows.show, show);
      commit("setShow", new_show);
    }

mutation:

    setShow(state, show) {
      Vue.set(state, "show", show);
    }

searchAPI:

export default {
    searchShowOnDB: function (showId) {
        return axios.get('/search/?id=' + showId);
    },
}

While everything appears to be functioning correctly with the API call and Vuex state updates reflecting properly in Vue Devtools, the form fields do not update automatically. Only when I interact with an input field or manually trigger a commit in Vue Devtools do the fields show_start, runtime, and description get updated.

Interestingly, the following snippet works flawlessly and updates all fields:

    async searchShowOnDB({ commit, rootState }, showId) {
      var show = {
        show_start: "2010-03-12",
        runtime: 60,
        description: "something"
      };
      var new_show = Object.assign(rootState.shows.show, show);
      commit("setShow", new_show);
    }

Despite trying various troubleshooting steps such as handling Promises explicitly, removing async/await and utilizing axios.get(...).then(...), rearranging code, nothing seems to resolve the issue.

Answer №1

Hey there! I noticed a small issue on line 15 in your /modules/search.js file where you are using Object.assign() on the rootState.search.show. Just a heads up, mutating the search property of the state directly is not recommended – it's best practice to only mutate inside mutations.

After that, you're trying to trigger the mutation but Vue detects that the value remains the same, so no component gets notified because there is no apparent change. Remember, it's crucial to avoid mutations outside of mutations!

To resolve this, simply commit the new show by replacing lines 15-16 with:

commit('setShow', show);

You can check out an example here: https://codesandbox.io/s/sharp-hooks-kplp7?file=/src/modules/search.js

This approach will completely replace state.show with the new value of show. If you want to merge the response into the current state.show, you can spread the contents like this:

commit("setShow", { ...rootState.search.show, ...show });

Additionally, you do not need to use Vue.set() within your mutation. Since the first parameter of any mutation is the module's state, you can simply assign state.show = show.

Lastly, as your Vuex store expands, consider namespace your modules to prevent potential naming conflicts.

Answer №2

It is crucial that all properties of objects in a state used in templates are present, or you must use Vue.set to add them.

  state: {
    show: {
      runtime: null // <- include this line
    }
  },

When using Vue.set for an entire object that already exists in the state without replacing it, only individual properties are updated. In this scenario, where you have an empty object and need to add the 'runtime' property, you can accomplish this by utilizing Object.assign. Additionally, all modifications to the state should be performed within mutations:

      var new_show = {
        runtime: response.data.url
      };
      commit("setShow", new_show);
...
  mutations: {
    setShow(state, new_show) {
      Object.assign(state.show, new_show)
    }
  },


Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the correct way to set up Vuetify on a Rails project?

Javascript Issue: [Vuetify] Encountered multiple Vue instances which led to errors. Check out https://github.com/vuetifyjs/vuetify/issues/4068 If you're facing the error "$attrs is readonly", it is due to: consoleError @ vuetify.js:22001 install @ ...

Stopping the execution of jQuery's .prop method does not result in any

Currently, I am trying to implement a feature where all radio buttons are unchecked one second after the page is loaded. I have come across an issue that has been causing me some frustration: alert('uncheck'); $("input[name=PreviousMailAID]:chec ...

Renewing Masonry and JQuery

Currently implementing Masonry from into a project aimed at creating a timeline effect for user interaction. The goal is to automatically refresh the page at intervals (every 10 seconds during testing), but encountered an issue. Upon initial load, the ge ...

Utilizing the array result obtained from the fetch function

Seeking assistance with a coding issue. I am puzzled as to why I am unable to utilize the data returned from an API call outside of its function, even though there are no errors occurring. The fetchUser function successfully retrieves the data from the API ...

Vue and Vuex: input value remains unchanged when there's no change in the store

<template> <input @input="formatInputValue" type="text" :value="formattedInput" /> </template> <script type="text/javascript"> import {formatPhoneNumber} from '~/utils/string'; export default { co ...

Having trouble retrieving JSON data using a jQuery ajax request

I am attempting to fetch information from data.php using a jQuery ajax call. Here is the code I am currently using: var jsonData; $.ajax({ url: 'data.php', success: function(response) { jsonData = response; ...

What is the best way to retrieve JavaScript Values through Selenium?

Currently, I am working with Java selenium client and running this code snippet. The variable PAGE_NUMBER is assigned a value; however, when using selenium, I'm unable to retrieve it: String script = "var cellValue = selenium.browserbot.getUserWindow ...

Ways to retrieve records within a specified date range in MongoDB?

I have a data record in my mongodb collection with the field "birth_date" set to "1983-05-06T16:26:32.613Z". Below is the find query I used to retrieve this record within a specific date range: var birthYear = 1983; var birthDateStart = new Date('1. ...

Tips for utilizing the beforeEach feature in node-tap?

Could someone please demonstrate how to utilize the beforeEach function? For more information, visit: . I am particularly interested in seeing an example using promises, although a callback version would also be appreciated. Below is a successfully functi ...

Adjust the width of the flex columns?

In one of my columns, I have a list that I'm splitting using CSS to wrap the data in the next column after a specific height. However, in the demo, you'll notice there's a lot of white space between the first and second columns. I'm uns ...

Challenges with jQuery's Hide/Show Functionality

I've been working on a hide/show function in jQuery that's giving me some trouble. The function includes an if/else statement that checks a data attribute in the HTML to determine whether to hide or show an element. While I can see that the funct ...

Status and route redirection in Vue instance management

I am looking to establish a global status property for my application using vue.js and vue-router. This property should be shared between components and used to control access to certain routes based on its value. For instance, I want to redirect all rout ...

How can the reset functionality of a function in an Angular 1.5 component's controller be implemented when transitioning to a different state?

I am facing an issue with my Angular 1.5 component and controller that uses the controllerAs syntax. I have written a function to add an extra css class to the component element if a specific html element exists on the page. However, when switching to a di ...

Using semaphores in a single-threaded asynchronous programming environment with async-await style

Semaphores function as a multi-threading locking mechanism to ensure only a limited number of threads can access a particular resource. Mutexes are a specialized case where the limitation is set to one thread. Asynchronous programming shares similarities ...

When importing OrbitControls in main.js, THREE.js does not include the EventDispatcher export

Description I've been working on integrating the OrbitControls from THREE.js into my project. However, I encountered an error message in the Google Chrome DevTools console when trying to import the OrbitControls object. The requested module '. ...

Interacting with wpdb using AngularJS

I just started learning AngularJS and I'm eager to implement it on my WordPress website. My goal is to display a table with data from a database in my WordPress site, but I am encountering difficulties accessing the WordPress functions and variables. ...

ref versus shallowRef for basic data types such as strings or numbers

After learning that shallowRef is more resource-efficient because it only monitors changes in array keys or direct values, rather than deep within object fields, I am intrigued. But what about strings or numbers? Would using shallowRef instead of ref have ...

Utilizing AngularJS with dual controllers within a single view

I recently started working on an angularJS web app using a purchased template that has all its controllers, routes, and directives in a single file called app.js. This is my first dive into angularJS and front-end development. Hoping to become a Full Stac ...

Changing the 'checked' attribute does not have any impact on how it appears in the browser

I am working on a button group where each button should light up when it is selected. The functionality is not fully working as expected; only one button should be active at a time. https://i.sstatic.net/oB9XG.png let stanceBar = ["long", "short", "out", ...

Displaying Google Street View and Google Maps with marker points in a parallel arrangement

Is there a way to align the Street View window with marker points from Google Maps? Here is the code that needs attention: <div id="property_map"></div> <script> /* Code for Google Map */ func ...