我应该如何避免在平面 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()
被不必要地一遍又一遍地调用。到目前为止,我解决这个问题的尝试都失败了或者不够优雅:
我试图在调用 fetchUser()
之前检查用户是否已经存在于 users
数组中。但是,这不起作用,因为 fetchUser
是一个异步操作。它可能正在获取过程中,因此检查用户是否 already 在数组中通常测试 false.
我试图检查用户是否已经存在于 addUser
突变中。虽然这确实可以防止重复,但不能防止用户进行不必要的提取。此外,addUser
突变必须在每次调用时检查用户是否重复,这对于较大的数组来说可能代价高昂。
一种可行的方法是在 users
状态下创建一个 fetchJobs
对象。当 fetchUser()
被调用时,我将用户的 id 添加到对象中。然后,在获取其他用户之前,我会检查这个对象以确保我没有获取重复项。与直接检查状态相反,这样做的原因是我在操作开始时提交了 fetchJob,因此它不是异步的。这样,其他组件和状态模块就可以访问它。但是,如果用户对象需要随时更新,这将不起作用,因为它仍将保留在 fetchJobs 对象中。
我还应该提到我正在使用一个名为 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)
}
})
},
我目前正在构建一个 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()
被不必要地一遍又一遍地调用。到目前为止,我解决这个问题的尝试都失败了或者不够优雅:
我试图在调用
fetchUser()
之前检查用户是否已经存在于users
数组中。但是,这不起作用,因为fetchUser
是一个异步操作。它可能正在获取过程中,因此检查用户是否 already 在数组中通常测试 false.我试图检查用户是否已经存在于
addUser
突变中。虽然这确实可以防止重复,但不能防止用户进行不必要的提取。此外,addUser
突变必须在每次调用时检查用户是否重复,这对于较大的数组来说可能代价高昂。一种可行的方法是在
users
状态下创建一个fetchJobs
对象。当fetchUser()
被调用时,我将用户的 id 添加到对象中。然后,在获取其他用户之前,我会检查这个对象以确保我没有获取重复项。与直接检查状态相反,这样做的原因是我在操作开始时提交了 fetchJob,因此它不是异步的。这样,其他组件和状态模块就可以访问它。但是,如果用户对象需要随时更新,这将不起作用,因为它仍将保留在 fetchJobs 对象中。
我还应该提到我正在使用一个名为 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)
}
})
},