【问题标题】:Vuex commit after await won't update state等待后的Vuex提交不会更新状态
【发布时间】:2020-08-13 16:11:33
【问题描述】:

我在这里和其他地方已经阅读了多个类似的问题,但我无法弄清楚。

我有一个带有 mapGetters 的表单和应该根据 Vuex 状态更新的输入值:

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

示例表单输入(我使用的是 Bootstrap Vue):

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

那我在表单组件上有这个方法:

    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");
      }
    },

以及对商店的此操作:

    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
      };
      //I'm updating the object since it could already contain something
      var new_show = Object.assign(rootState.shows.show, show);
      commit("setShow", new_show);
    }

变异:

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

搜索API:

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

一切正常,API 调用被执行,我什至可以在 Vue Devtools 中看到 Vuex 更新状态,但表单没有更新。 只要我在输入字段中写入内容或在 Vue Devtools 中点击 commit,表单字段 show_startruntimedescription 都会更新。

此外,这可以正常工作并更新所有内容:

    async searchShowOnDB({ commit, rootState }, showId) {
      var show = {
        show_start: "2010-03-12",
        runtime: 60,
        description: "something"
      };
      //I'm updating the object since it could already contain something
      var new_show = Object.assign(rootState.shows.show, show);
      commit("setShow", new_show);
    }

我不知道还能做什么,我尝试明确解决 Promises,删除 async/await 并使用 axios.get(...).then(...),移动一些东西......似乎没有任何效果。

【问题讨论】:

  • 也许可以尝试复制该问题,但请以较小的规模与我们分享:) 通过 CodeSandbox 或 JSFiddle
  • 我在这里复制了它:codesandbox.io/s/brave-sun-yjl36 - 新窗口:yjl36.csb.app - 只需输入名称并点击搜索。什么都不会改变。那么一旦你编辑输入,我需要的就会出现。

标签: javascript vue.js async-await vuex


【解决方案1】:

15/modules/search.js 上,您在rootState.search.show 上使用Object.assign()。这会改变 statesearch 属性(这是错误的,顺便说一句,你应该只在突变内部进行突变!)。阅读下面的原因。

然后你试图触发突变。但猜猜怎么了? Vue 看到它是相同的值,所以没有通知组件,因为没有变化。这就是为什么您应该永远在突变之外进行突变!

因此,不要将值分配给您的操作中的状态,只需提交新节目(将行 15-16 替换为:

 commit('setShow', show);

在这里查看:https://codesandbox.io/s/sharp-hooks-kplp7?file=/src/modules/search.js

这将用show 完全替换state.show。如果您只想将响应合并到当前state.show(以保留您添加到当前show 的一些自定义内容),您可以传播state.show 的内容并用show 的内容覆盖:

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

另请注意,您的突变不需要Vue.set()。您在任何突变的第一个参数中都有state,这就是当前模块的state。所以只需分配state.show = show

最后一点:当你的 vuex 变大时,你可能想namespace你的模块,以避免任何名称冲突。

【讨论】:

  • 知道了!我想我得到了Object.assign() 错误:我认为它只返回了更新的对象而没有更改它。谢谢!我还将命名我的模块。
  • @koichirose Object.assign 的主要工作是分配(改变作为第一个参数传入的对象)。它还返回变异对象这一事实更像是一个不错的功能(如果您愿意,这是一个副产品),因为您不必将该赋值作为单独的表达式运行。您实际上可以在另一个表达式中运行它并使用返回的对象。
【解决方案2】:

在模板中使用的状态中对象的所有道具必须存在,或者您应该为此类属性调用 Vue.set。

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

你为整个对象调用了 Vue.set,但它已经存在于状态中,你不用一个新的来替换它,你只是替换了 props。在您的情况下,您有一个空对象并使用 Object.assign 添加“运行时”支持它。 此外,所有状态操作都应在突变中完成:

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


【讨论】:

    猜你喜欢
    • 2019-08-08
    • 1970-01-01
    • 2020-05-30
    • 2021-02-05
    • 2022-01-16
    • 1970-01-01
    • 2021-06-19
    • 2019-11-30
    • 2020-11-23
    相关资源
    最近更新 更多