Vuex commit после await не обновляет состояние - PullRequest
0 голосов
/ 29 апреля 2020

Я читал несколько похожих вопросов об этом здесь и в других местах, но я не могу понять это.

У меня есть форма с 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);
    }

searchAPI:

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

Все работает, вызов API выполнен, Я даже могу видеть обновленное состояние Vuex в Vue Devtools, но форма не обновляется. Как только я что-то пишу в поле ввода или нажимаю commit в Vue Devtools, поля формы show_start, runtime, description все обновляются.

Кроме того, это работает правильно и обновляет все:

    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(...), перемещая вещи ... кажется, ничего не работает .

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

На линии 15 вашего /modules/search.js, который вы используете Object.assign() на rootState.search.show. Это мутирует search опору state (что неверно, кстати, , вы должны мутировать только внутри мутаций !). Читайте ниже, почему.

И затем вы пытаетесь вызвать мутацию. Но угадайте что? Vue видит, что это то же самое значение, поэтому ни один компонент не уведомляется, потому что не было никаких изменений. Вот почему вы должны никогда мутировать вне мутаций!

Так что вместо того, чтобы присваивать значение состоянию в вашем действии, просто передайте новое шоу (замените линии 15-16 с:

 commit('setShow', show);

Смотрите здесь: https://codesandbox.io/s/sharp-hooks-kplp7?file= / src / modules / search. js

Это полностью заменит state.show с show. Если вы хотите только объединить ответ с текущим state.show (чтобы сохранить некоторые пользовательские элементы, добавленные к текущему show), вы можете распространить содержимое state.show и перезаписать содержимым show:

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

Также обратите внимание, что вам не нужно Vue.set() в вашей мутации. У вас есть state в первом параметре любой мутации, и это state текущего модуля. просто назначьте state.show = show.

И последнее замечание: когда ваш vuex становится больше, вы можете захотеть namespace ваших модулей, чтобы избежать любых конфликтов имен.

0 голосов
/ 29 апреля 2020

Все реквизиты объектов в состоянии, используемом в шаблонах, должны существовать, или вы должны вызвать Vue .set для таких свойств.

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

Вы вызываете Vue .set для всего объекта, но он уже существует в состоянии, и вы не заменяете его новым, вы просто заменяете реквизит. В вашем случае у вас есть пустой объект и вы добавляете «runtime» для его поддержки с помощью Object.assign. Также все манипуляции с состоянием должны выполняться в мутациях:

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


...