使用 Vue + Vuex 在渲染之前无法获取对象的状态属性

Posted

技术标签:

【中文标题】使用 Vue + Vuex 在渲染之前无法获取对象的状态属性【英文标题】:Cannot get object’s property in state before render using Vue + Vuex 【发布时间】:2017-07-08 07:10:56 【问题描述】:

我有一个 Vuex 存储,其中包含一个名为 data 的对象,该对象处于名为 users 的模块状态。此对象将用户 ID 映射到用户,并且开始为空。

然后我有一个消息列表组件,它使用名为 authorId 的传递属性呈现消息组件。此消息将使用 id 尝试通过在商店中搜索数据对象来获取作者的电子邮件。如果没有找到,它会派发一个动作,从服务器获取用户并提交一个突变以将 id 和用户添加到存储中的数据对象。请注意,目前每条消息都具有相同的 authorId,并且服务器获取逻辑按预期工作。

用户模块

state:  data:  ,
mutations: 
  setUser(state, user) 
    Vue.set(state.data, user._id, user);
  ,
,
actions: 
  fetchUser( commit , id) 
    userService.find( _id: id ).then((response) => 
      commit('setUser', response.data[0]);
    );
  

消息组件

<template>
<div class="message">
  <strong v-if="author">author.email</strong>: text
</div>
</template>

<script>
export default 
  name: 'messages',
  props: ['text', 'authorId'],
  created() 
    this.resolveAuthor();
  ,
  computed: 
    author() 
      return this.$store.state.users.data[this.authorId];
    ,
  ,
  methods: 
    resolveAuthor() 
      if (!this.author) this.$store.dispatch('fetchUser', this.authorId);
  ,
;
</script>

预期的行为将是只看到一个 setUser 突变,因为第一个消息组件实例将获取并填充存储,而下一个实例将使用该存储的值。我看到每条消息都有一个突变,这意味着在 created() 或 Mounted() 中对 this.author 的调用始终未定义,也许我希望在第一条消息中但不会在下一条消息中出现这种情况,因为商店已经填充。

在每个消息实例的每个 created() 或 mounted() 中执行 console.log(Object.keys(this.$store.state.users.data)) 显示数据对象是空的,但我可以看到它有一个键(authorId)和 vue 开发工具中的用户值,如果我使用 console.log(this.$store.state.users.data)。

此外,如果我在模板中渲染 this.user,它将在每条消息上正确打印数据。此外,如果我重新保存任何文件,热重新加载现在将打印我之前所做的所有 console.log(Object.keys(this.$store.state.users.data)) 但现在显示我期望的键和值显示一个空对象。

编辑 2018-10-24 我希望工作存储库可以帮助某人:https://github.com/niklabaz/chatter

【问题讨论】:

【参考方案1】:

我认为你有一个竞争条件。您正在循环和创建组件,然后当您创建每个组件(消息)时,您希望获取创建 msg 的用户。现在我认为发生的事情是您创建了第一个组件,它没有检测到数据中的用户,因此它尝试获取它,但是在该用户通过 api 之前(即使是几毫秒也需要时间)您渲染另一个组件并且 data.users 仍未填充,它会发送另一个 api 请求。请记住,vue 不会等待一个 api 请求返回数据来循环渲染另一个组件。如果这是真的并且我是正确的,那么您将需要重组您的组件结构或至少以不同的方式获取用户。

编辑

我的建议是修改您的服务器端代码,以便它发送一个用户对象(或至少他们的 uname 和 id )作为每个消息对象的一部分。即使您不使用 ORM,您也可以将具有 user_id FK 的 msg 表与 users 表连接起来。然后您在父组件中获取所有这些数据,然后当您循环浏览消息时,您将获得所需的所有用户信息。

【讨论】:

我也是这样,所以我尝试让动作返回一个承诺,并在 resolveAuthor() 中调度动作,然后 .then() 将名为 authorEmail 的本地属性关联到商店中的那个(假设 fetch 操作成功完成)。在这种情况下,Vue 必须等待这条消息获取才能呈现下一条消息,对吧?但我看到同样的行为发生了。 不,如果你从一个动作中返回一个承诺,你可以将 .then 链接到你发送动作的地方。所以this.$store.dispatch ('action', id).then((res) =&gt; // js will wait for response here ) 但渲染另一个 msg 组件与此无关......当在循环中渲染组件时,您返回的承诺不会停止循环。 这可能是问题所在。如果在父组件中而不是执行 我执行 并在此 div 中检查作者是否可用并在需要时获取它(使用一个承诺)那么循环应该暂停或者这不是一个解决方案? 即使在渲染消息时 store 不可用,也应该在填充 store 后更新它们,因为它们使用响应式属性。 然后尝试为您尝试显示和存储的所有消息获取所有用户,然后在需要时获取它们。

以上是关于使用 Vue + Vuex 在渲染之前无法获取对象的状态属性的主要内容,如果未能解决你的问题,请参考以下文章

vue 数组和对象渲染问题

vue父组件异步获取数据传值给子组件

在 Vue 和 Vuex 的非子组件中获取存储值

Vue 看不到我的对象从 vuex 获取的更新

Vue2 + Vuex Commit Not Committing(没有 Vue devtools)

Vue、Vuex、JavaScript:includes() 无法按预期工作