我目前正在构建一个vue/vuex/firestore/vuexFire项目,遇到了以下问题。
假设我想显示一个消息列表,其中每条消息都与一个用户相关联。一个用户可以提交多条消息,这些消息都将在他们的名下。在vuex中,这方面的平面表示可能看起来像:
用户状态模块
state: () => ({
users: [
{
name: 'foo',
id: 'bar'
}
//...
]
})
消息状态模块
state: () => ({
messages: [
{
message: 'blah blah',
authorId: 'bar'
}
//...
]
})
在服务器上(我使用的是Firebase的Firestore(,结构基本相同。所以,我获取所有的消息,然后像这样关注每个作者:
// 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()
被不必要地反复调用。到目前为止,我解决这个问题的尝试已经失败或不雅:
在调用
fetchUser()
之前,我试图检查用户是否已经存在于users
数组中。但是,这不起作用,因为fetchUser
是一个异步操作。它可能正在获取过程中,因此检查用户是否已经在数组中通常测试为false。我试着检查用户是否已经出现在
addUser
突变中。虽然这确实可以防止重复,但并不能防止不必要的用户获取。此外,addUser
突变必须在每次调用中检查用户是否重复,这对于较大的数组来说可能很昂贵。一种行之有效的方法是在
users
状态下创建一个fetchJobs
对象。当调用fetchUser()
时,我将用户的id添加到对象中。然后,在获取其他用户之前,我会检查这个对象,以确保我没有获取重复的用户。与直接检查状态相反,这之所以有效,是因为我在操作开始时提交了fetchJob,所以它不是异步的。这样,其他组件和状态模块就可以访问它。但是,如果用户对象在任何时候都需要更新,这将不起作用,因为它仍将保留在fetchJobs对象中。
我还应该提到,我正在使用一个名为VuexFire的小助手库,它管理FirestorecollectionReference.onSnapshot()
的绑定。这引入了另一个限制,即当添加、更新或删除文档时,我不能直接运行操作。这是因为VuexFire会自动处理所有这些更改,并且不支持挂接这些事件。相反,我必须循环浏览所有现有的消息并调用fetchUser()
。我没有在上面的代码示例中包括这一点,因为它与snapshot.forEach()
没有太大区别。如果需要的话,我也可以放弃这个图书馆。
那么,解决这个问题的最佳方法是什么呢?
从您键入的所有内容来看,防止fetchUser
操作被不必要地调用似乎是至关重要的,所以我将重点关注您尝试过的一次尝试,以防止这种情况发生
我试图检查用户是否已经存在于用户数组中然后调用fetchUser((。然而,这不起作用,因为fetchUser是一个异步操作。它可能正在获取,因此检查用户是否已经在数组中通常测试错误
这个怎么样?
{
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)
}
})
},