确保在渲染组件之前加载 Vuex 状态

Posted

技术标签:

【中文标题】确保在渲染组件之前加载 Vuex 状态【英文标题】:Ensure that Vuex state is loaded before render component 【发布时间】:2019-01-19 22:14:00 【问题描述】:

我有一个add-user.vue 组件。这是我添加新用户和编辑现有用户的模板。所以在页面加载时,我检查路由是否有id,如果有,我从状态数组加载用户来编辑它。我的问题是 user 未定义,因为状态数组 users 为空。如何确保我的用户对象不是未定义的。它有时会加载,但刷新时不会。我以为我把它盖住了,但没有。这是我的设置。我在这里错过了什么?

商店

state: 
  users: []
,

getters: 
  users: state =>
    _.keyBy(state.users.filter(user => user.deleted === false), 'id')
,

actions: 
  fetchUsers(
    commit
  ) 
    axios
      .get('http://localhost:3000/users')
      .then(response => 
        commit('setUsers', response.data);
      )
      .catch(error => 
        console.log('error:', error);
      );
  

在我的 add-user.vue 组件中,data() computed:created() 中有以下内容

data() 
  return 
    user: 
      id: undefined,
      name: undefined,
      gender: undefined
    
  ;
,

computed: 
  ...mapGetters(['users'])
,

created() 
  if (this.$route.params.userId === undefined) 
    this.user.id = uuid();
    ...
   else 
    this.user = this.users[this.$route.params.userId];
  

模板

<template>
  <div class="add-user" v-if="user"></div>
</template>

我的User.vue 我有以下设置,我在created() 上初始化用户获取

<template>
  <main class="main">
    <AddUser/>
    <UserList/>
  </main>
</template>

<script>
import AddUser from '@/components/add-user.vue';
import UserList from '@/components/user-list.vue';

export default 
    name: 'User',

    components: 
        AddUser,
        UserList
    ,

    created() 
        this.$store.dispatch('fetchUsers');
    
;
</script>

我已经试过了。保存在我的编辑器中时它可以工作,但不能刷新。 dispatch().then() 在用户设置 mutation 之前运行。

created() 
  if (this.$route.params.userId === undefined) 
    this.user.id = uuid();
    ...
   else 
    if (this.users.length > 0) 
                this.user = this.users[this.$route.params.userId];
             else 
                this.$store.dispatch('fetchUsers').then(() => 
                    this.user = this.users[this.$route.params.userId];
                );
            
  

【问题讨论】:

很可能计算值还没有映射到created 钩子中。尝试在created 中使用this.$store.getters.users 或将您的代码移动到mounted 钩子中 @JacobGoh 据我了解,在创建 getters 没有区别,因为它是反应性的。当fetchUsers 完成后,getter 将具有价值。 我建议您始终预计用户未加载 - 所以首先检查它是否在商店中。如果是 - 那么只需使用它。否则分派一个 AJAX 请求来加载它。 【参考方案1】:

我会在User.vue 中使用beforeRouteEnter,以便在加载数据之前不会初始化组件。 (假设您使用的是vue-router

beforeRouteEnter (to, from, next) 
    if (store.state.users.length === 0) 
        store.dispatch(fetchUsers)
        .then(next);
    
,

你需要 import store from 'path/to/your/store' 因为在组件初始化之前this.$store 不可用。

【讨论】:

【参考方案2】:

虽然这解决了,但我会回答未来的人。您可以按照 Shu 的建议提前发出 dispatch,或者您仍然可以在同一组件上调度 mounted 钩子,但使用一些状态变量来跟踪进度:

data:
    ...
    loading:false,
    ...
,
...
mounted()
this.loading = true,
this.$store
  .dispatch('fetchUsers')
  .finally(() => (this.loading=false));

然后在您的模板中使用此loading 状态变量来呈现页面或呈现一些微调器或进度条:

<template>
    <div class='main' v-if="!loading">
        ...all old template goes her
    </div>
    <div class="overlay" v-else>
        Loading...
    </div>
</template>

<style scoped>
    .overlay 
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 10;
      color: #FFFFFF;
    
</style>

【讨论】:

【参考方案3】:

对于这种特殊情况,它只是在同一个 vue 实例中来回切换。通过添加:key="some-unique-key"解决了它,所以它看起来像这样。

<template>
  <main class="main">

    <AddUser :key="$route.params.userId"/>

    <UserList/>

  </main>
</template>

【讨论】:

以上是关于确保在渲染组件之前加载 Vuex 状态的主要内容,如果未能解决你的问题,请参考以下文章

vuex + watch = 监听组件渲染状态

Vuex 全局状态更改不会触发 Nuxt 中 v-for 循环中的重新渲染组件

Vue 计算属性已更新,但组件未重新渲染

使用 Lodash.remove 通过 Vuex 突变更改状态不会触发我的 Vue 组件中的反应式重新渲染

状态渲染前的 Vue.js/vuex getters 错误

如何在 React JS 中渲染之前等待状态?