等待VueX值加载,然后再加载组件

时间:2019-06-13 19:59:10

标签: javascript vue.js vuejs2 vuex vue-router

当用户尝试直接导航以加载组件url时,我的vuex操作中将进行一次http调用,它将在解析后在我的状态下定义一个值。

在解析http调用并定义状态值之前,我不希望加载组件。

例如,在我的组件中

export default {
  computed: {
    ...mapState({
      // ** this value needs to load before component mounted() runs **
      asyncListValues: state => state.asyncListValues
    })
  },

  mounted () {
    // ** I need asyncListValues to be defined before this runs **
    this.asyncListValues.forEach((val) => { 
      // do stuff
    });
  }
}

如何在加载组件之前让组件等待asyncListValues加载?

4 个答案:

答案 0 :(得分:1)

一种方法是将您的组件分为两个不同的组件。一旦数据准备就绪,新的父组件就可以处理数据的获取并呈现子组件。

ParentComponent.vue

<template>
  <child-component v-if="asyncListValues && asyncListValues.length" :asyncListValues="asyncListValues"/>
  <div v-else>Placeholder</div>
</template>
<script>
export default {
  computed: {
    ...mapState({
      asyncListValues: state => state.asyncListValues
    })
  }
}
</script>

ChildComponent.vue

export default {
  props: ["asyncListValues"],
  mounted () {
    this.asyncListValues.forEach((val) => { 
      // do stuff
    });
  }
}

答案 1 :(得分:1)

由于您在问题中提到了vue-router,因此可以使用beforeRouteEnter来推迟渲染组件。

例如,如果您有一条称为“照片”的路线:

import Photo from "../page/Photo.vue";

new VueRouter({
  mode: "history",
  routes: [
    { name: "home", path: "/", component: Home },
    { name: "photo", path: "/photo", component: Photo }
  ]
});

您可以像这样使用beforeRouteEnter

<template>
  <div>
    Photo rendered here
  </div>
</template>
<script>
export default {
  beforeRouteEnter: async function(to, from, next) {
    try {
      await this.$store.dispatch("longRuningHttpCall");

      next();
    } catch(exception) {
      next(exception);
    }
  }
}
</script>

它的作用是,等待操作完成,根据需要更新状态,然后对next()的调用将告诉路由器继续该过程(在{{1}内部渲染组件) }。

如果需要一个少用ES6的示例(如果您不使用此语法),请告诉我。

您可以在此页面上检查official documentation of beforeRouteEnter,还会发现您也可以使用<router-view></router-view>将其放在路线级别。

答案 2 :(得分:1)

方法是存储状态值。

例如,如果您的商店依赖单个API,则可以执行以下操作。但是,对于多个API,最好单独存储每个api加载状态,或为每个API使用专用对象。

通常可以有4种状态,我更希望在可全局访问的模块中具有这些状态:

// enums.js
export default {
  INIT: 0,
  LOADING: 1,
  ERROR: 2,
  LOADED: 3
};

然后,您可以将变量存储在vuex状态下,其中apiState用INIT初始化。您也可以使用[]初始化数组,但这不是必须的。

import ENUM from "@/enums";
// store.js
export default new Vuex.Store({
  state: {
    apiState: ENUM.INIT,
    accounts: [],
    // ...other state
  },
  mutations: {
    updateAccounts (state, accounts) {
      state.accounts = accounts;
      state.apiState = ENUM.LOADED;
    },
    setApiState (state, apiState) {
      state.apiState = apiState;
    },
  },
  actions: {
    loadAccounts ({commit) {
      commit('setApiState', ENUM.ERROR);
      somFetchInterface()
        .then(data=>commit('updateAccounts', data))
        .catch(err=>commit('setApiState', ENUM.ERROR))
    }
  }
});

然后,通过添加一些computed,您可以切换显示哪个组件。这显示了使用状态的好处,因为您可以轻松识别Error状态,并在状态未准备好时显示加载动画。

<template>
  <ChildComponent v-if="apiStateLoaded"/>
  <Loader v-if="apiStateLoading"/>
  <Error v-if="apiStateError"/>
</template>
<script>
import ENUM from "@/enums";
export default {
  computed: {
    ...mapState({
      apiState: state=> state.apiState
    }),
    apiStateLoaded() {
      return this.apiState === ENUM.LOADED;
    },
    apiStateLoading() {
      return this.apiState === ENUM.LOADING || this.apiState === ENUM.INIT;
    },
    apiStateError() {
      return this.apiState === ENUM.ERROR;
    },
  })
}
</script>

或者,如果仅使用空数组asyncListValues初始化商店中的[],则可以避免出现期望数组的错误。

答案 3 :(得分:0)

对我来说简单的方法:

<textarea>