【问题标题】:Wait for data in mapstate to finish loading等待mapstate中的数据完成加载
【发布时间】:2021-02-07 17:25:25
【问题描述】:

我在Vuex 中存储了一个userProfile,以便能够在我的整个项目中访问它。但是如果我想在created() 钩子中使用它,配置文件还没有加载。该对象存在,但其中没有存储数据。至少在页面的初始加载时。如果我稍后访问它(例如通过单击按钮),一切都会完美运行。 有没有办法等待数据加载完成?

这是userProfileVuex 中的设置方式:

mutations: {
    setUserProfile(state, val){
      state.userProfile = val
    }
},
actions: {
    async fetchUserProfile({ commit }, user) {
      // fetch user profile
      const userProfile = await fb.teachersCollection.doc(user.uid).get()
  
      // set user profile in state
      commit('setUserProfile', userProfile.data())
    },
}

这是我想要访问它的代码:

<template>
<div>
  <h1>Test</h1>
  {{userProfile.firstname}}
  {{institute}}
</div>
</template>


<script>
import {mapState} from 'vuex';

export default {
  data() {
    return {
      institute: "",
    }
  },
  computed: {
      ...mapState(['userProfile']),
  },
  created(){
    this.getInstitute();
  },

  methods: {
    async getInstitute() {
      console.log(this.userProfile); //is here still empty at initial page load

      const institueDoc = await this.userProfile.institute.get();
      if (institueDoc.exists) {
        this.institute = institueDoc.name;
      } else {
        console.log('dosnt exists') 
      }
      
    }
  }
}
</script>

通过控制台登录,发现问题出在代码运行的顺序上。首先,运行方法getInstitute,然后运行action,然后运行mutation。 我尝试添加一个loaded 参数并使用await 来解决这个问题,但没有任何效果。

【问题讨论】:

    标签: javascript vue.js vuejs2 async-await vuex


    【解决方案1】:

    即使您使 createdmounted 异步,它们也不会延迟您的组件渲染。他们只会延迟await之后的代码的执行。

    如果您不想在userProfile 拥有id(或您的用户拥有的任何其他属性)之前渲染模板的一部分(或全部),只需使用v-if

    <template v-if="userProfile.id">
      <!-- your normal html here... -->
    </template>
    <template v-else>
       loading user profile...
    </template>
    

    要在userProfile 更改时执行代码,您可以在其内部属性之一上放置watcher。在您的情况下,这应该有效:

    export default {
      data: () => ({
        institute: ''
      }),
      computed: {
        ...mapState(['userProfile']),
      },
      watch: {
        'userProfile.institute': {
          async handler(institute) {
            if (institute) {
              const { name } = await institute.get();
              if (name) {
                this.institute = name;
              }
            } 
          },
          immediate: true
        }
      }
    }
    

    旁注:Vue 3 为这种模式提供了一个内置的解决方案,称为Suspense。不幸的是,它只在少数地方被提及,它没有(还)被正确记录,并且有迹象表明 API 可能会改变。
    但它非常棒,因为渲染条件可以与父级完全解耦。它可以包含在悬浮的孩子中。孩子声明的唯一内容是:“我正在加载”“我已经完成加载”。当所有 suspensibles 都准备好后,就会渲染模板默认值。
    此外,如果子项是动态生成的并推送了新的子项,则父悬念切换回回退(加载)模板,直到加载新添加的子项。这是开箱即用的,您需要做的就是在 children 中声明 mounted async。
    简而言之,您对 Vue 2 的期望。

    【讨论】:

    • 谢谢,但这并不能解决我的所有问题。我需要在加载userProfile 时执行getInstitute 方法以获取我需要显示的更多信息。有没有办法做到这一点?也感谢您提供有关&lt;Suspense&gt; 的信息。真的很酷!
    • @Sumny,这可以在watch 中完成(更新了答案)。但是你为什么不从你收到userProfile 响应的地方触发额外的代码呢?您可以简单地将其放在不同的操作中并调度它。
    • @tao 谢谢。我在商店里试过了,但它没有用,因为我需要再次在创建的钩子中使用它。实际上,我的问题很简单:每个用户都与一个机构相关联。在我的 firebase 后端中,每个机构都有不同的集合:例如“insitut1_events”和“institut2_events”。我现在需要根据用户设置正确的集合。我只是想不通这是怎么回事
    • 如果您需要 created 钩子中的一些数据,您只需在获得该数据之前不渲染组件。在您的应用组件(或您选择的任何父组件)中放置一个 “正在加载数据...” div。拨打电话。当它解析时,将其推送到存储并使用简单的v-if/v-else“正在加载...” div 之间切换到您想要使用该数据呈现的任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    相关资源
    最近更新 更多