【问题标题】:Ensure that Vuex state is loaded before render component确保在渲染组件之前加载 Vuex 状态
【发布时间】: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 请求来加载它。

标签: vue.js vue-component vuex


【解决方案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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-19
        • 1970-01-01
        • 2019-12-31
        • 2019-12-12
        • 2021-03-07
        • 2019-11-03
        • 2021-01-18
        • 2017-08-30
        相关资源
        最近更新 更多