确保在渲染组件之前加载 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 全局状态更改不会触发 Nuxt 中 v-for 循环中的重新渲染组件