我应该如何避免在平面 vuex 结构中重复数据和 API 调用?

How should I avoid duplicate data and API calls in a flat vuex structure?

我目前正在构建一个 vue/vuex/firestore/vuexFire 项目,我 运行 进入以下问题。

假设我想显示一个消息列表,其中每条消息都与一个用户相关联。一个用户可以提交多条消息,这些消息都将在他们的名字下。在 vuex 中,它的平面表示可能如下所示:

用户态模块

state: () => ({
  users: [
   {
    name: 'foo',
    id: 'bar'
   }
   //...
  ]
})

消息状态模块

state: () => ({
  messages: [
   {
    message: 'blah blah',
    authorId: 'bar'
   }
   //...
  ]
})

在服务器上(我使用的是 Firebase 的 Firestore)结构基本相同。所以,我获取所有消息,然后像这样关注每个 authorId:

// action in the vuex messages module
{
 fetchMessages: async ({ commit, dispatch }) => {
  
  const snapshot = await firestore.collection('messages').get();
  snapshot.forEach((doc) => {
   
   // commit the document
   commit('addMessage', doc.data())
   
   // fetch the associated user
   dispatch('fetchUser', doc.data().authorId)
  })
 },

 fetchUser: async ({commit}, id) => {
  const user = await firestore.collection('users').doc(id).get();
  commit('addUser', user.data())
 }

}

我遇到的问题是,如果有一个用户创建了多条消息,它们将被一遍又一遍地添加到用户数组中。此外, fetchUser() 被不必要地一遍又一遍地调用。到目前为止,我解决这个问题的尝试都失败了或者不够优雅:

我还应该提到我正在使用一个名为 VuexFire 的小型帮助程序库,它管理 Firestore collectionReference.onSnapshot() 的绑定。这引入了另一个限制,即我不能在添加、更新或删除文档时直接 运行 一个动作。这是因为 VuexFire 会自动处理所有这些更改,并且不支持挂钩这些事件。相反,我必须遍历所有现有消息并调用 fetchUser()。我没有在上面的代码示例中包含它,因为它与 snapshot.forEach() 没有太大区别。如果需要,我也可以放弃这个库。

那么,解决这个问题的最佳方法是什么?

从您输入的所有内容来看,防止 fetchUser 操作被不必要地调用似乎是最重要的,所以我将专注于您尝试过的一次尝试,以防止这种情况发生

I tried to check if the user is already present in the users array before calling fetchUser(). However, this doesn't work, because fetchUser is an async operation. It could be in the process of fetching, so checking to see if the user is already in the array usually tests false

这个怎么样?

{
 fetchMessages: async ({ commit, dispatch }) => {
  
  const snapshot = await firestore.collection('messages').get();
  snapshot.forEach((doc) => {
   
   // commit the document
   commit('addMessage', doc.data())
   
   const userIndexInTheUsersStoreArray = store.state.users.findIndex(user => user.id === doc.data().authorId)
   
   const isUserInTheUsersStoreArray = userIndexInTheUsersStoreArray > -1
   
   if (!userInTheUsersStoreArray) {
    dispatch('fetchUser', doc.data().authorId)
   }
  })
 },