Vuex访问状态BEFORE异步操作完成

时间:2017-06-20 06:09:31

标签: vue.js state vuejs2 vue-component vuex

我遇到的问题是计算的getter在更新之前访问状态,从而呈现旧状态。我已经尝试过一些方法,例如将变量与动作合并,并将状态更改为许多不同的值,但在调度完成之前仍然会调用getter。

问题

在异步操作(api调用)完成之前访问状态。

代码结构

  1. 组件A加载API数据。
  2. 用户点击其中一项数据。
  3. 组件A将单击的数据(对象)调度到组件B。
  4. 组件B加载收到的对​​象。
  5. 注意

    DOM呈现得很好。这是一个CONSOLE ERROR。 Vue始终关注DOM更改并立即重新呈现。然而,控制台会接收所有内容。

    目标

    防止组件B(仅称为AFTER组件)在组件A的分派完成之前运行其计算的getter方法。

    Store.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios';
    
    Vue.use(Vuex);
    
    export const store = new Vuex.Store({
    
      state: {
        searchResult: {},
        selected: null,
      },
    
      getters: {
        searchResult: state => {
          return state.searchResult;
        },
        selected: state => {
          return state.selected;
        },
      },
    
      mutations:{
        search: (state, payload) => {
          state.searchResult = payload;
        },
        selected: (state, payload) => {
          state.selected = payload;
        },
      },
    
      actions: {
        search: ({commit}) => {
          axios.get('http://api.tvmaze.com/search/shows?q=batman')
            .then(response => {
              commit('search', response.data);
            }, error => {
              console.log(error);
            });
        },
    
        selected: ({commit}, payload) => {
          commit('selected', payload);
        },
      },
    
    });
    

    SearchResult.vue

    <template>
    <div>
      //looped
      <router-link to="ShowDetails" @click.native="selected(Object)"> 
          <p>{{Object}}</p>
      </router-link>
    </div>
    </template>
    
    <script>
    export default {
      methods: {
        selected(show){
          this.$store.dispatch('selected', show);
        },
      },
    }
    </script>
    

    ShowDetails.vue

    <template>
    <div>
      <p>{{Object.name}}</p>
      <p>{{Object.genres}}</p>
    </div>
    </template>
    
    <script>
    export default {
      computed:{
        show(){
          return this.$store.getters.selected;
        },
      },
    }
    </script>
    

    This image shows that the computed method "show" in file 'ShowDetails' runs before the state is updated (which happens BEFORE the "show" computed method. Then, once it is updated, you can see the 2nd console "TEST" which is now actually populated with an object, a few ms after the first console "TEST".

    问题

    Vuex是关于状态观察和管理的,所以如何防止此控制台错误?

    提前致谢。

3 个答案:

答案 0 :(得分:5)

store.dispatch可以处理触发的动作处理程序返回的Promise,它也返回Promise。请参阅Composing Actions

您可以设置所选操作以返回此类承诺:

selected: ({commit}, payload) => {
    return new Promise((resolve, reject) => {
        commit('selected', payload);
    });
} 

然后在 SearchResults.vue 中,而不是使用router-link使用按钮,并在所选操作的成功回调中执行programmatic navigation承诺这样:

<template>
<div>
  //looped
  <button @click.native="selected(Object)"> 
      <p>{{Object}}</p>
  </button>
</div>
</template>

<script>
export default {
  methods: {
    selected(show){
      this.$store.dispatch('selected', show)
          .then(() => {
            this.$router.push('ShowDetails');
        });
    },
  },
}
</script> 

答案 1 :(得分:1)

如果没有搜索结果,您可以尝试使用v-if来避免渲染模板

v-if="$store.getters.searchResult"

答案 2 :(得分:0)

初始化您的州。 与所有其他Vue&#39;一样数据总是更好地在起始点初始化它,即使是空''[]但是VueJS(不确定Angular或React行为是否相同,但我认为相似)会表现得更好所有的变量都已初始化。

您可以在商店实例中定义状态的初始空值。

您会发现这不仅对此有帮助,而且例如使用表单验证,因为大多数插件可以正常使用初始化数据,但无法正常使用非初始化数据。

希望它有所帮助。