В настоящее время я создаю проект vue / vuex / firestore / vuexFire и столкнулся со следующей проблемой:
Скажем, я хочу отобразить список сообщений, в которых каждое сообщение связано с пользователем. Пользователь может отправить несколько сообщений, и все они будут на свое имя. В vuex плоское представление этого может выглядеть так:
Модуль состояния пользователя
state: () => ({
users: [
{
name: 'foo',
id: 'bar'
}
//...
]
})
Модуль состояния сообщений
state: () => ({
messages: [
{
message: 'blah blah',
authorId: 'bar'
}
//...
]
})
На сервере (я использую Firebase's 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()
вызывается без надобности снова и снова. До сих пор мои попытки решить эту проблему не увенчались успехом или были неэлегантными:
Я попытался проверить, присутствует ли пользователь в массиве users
, прежде чем вызывать fetchUser()
. Однако это не работает, потому что fetchUser
является асинхронной операцией c. Это могло быть в процессе выборки, поэтому проверка того, есть ли у пользователя уже в массиве, обычно проверяет false.
Я пытался проверить, есть ли у пользователя уже присутствует в мутации addUser
. Хотя это предотвращает дублирование, это не предотвращает ненужную выборку пользователем. Кроме того, мутация addUser
должна проверять, что пользователь не является дубликатом при каждом вызове, что может быть дорогостоящим с большими массивами.
Один из подходов, который работал, - это создание fetchJobs
объект в состоянии users
. Когда был вызван fetchUser()
, я добавил к объекту идентификатор пользователя. Затем, прежде чем получать дополнительных пользователей, я бы проверил этот объект, чтобы убедиться, что я не получаю дубликат. Причина, по которой это сработало, в отличие от прямой проверки состояния, заключается в том, что я зафиксировал fetchJob в начале действия, поэтому он не был асинхронным. Таким образом, другие компоненты и модули состояния могли получить к нему доступ. Однако это не работает, если пользовательский объект необходимо обновить в любой момент, поскольку он все равно останется в объекте fetchJobs.
Я также должен упомянуть, что я использую небольшой вспомогательная библиотека VuexFire, которая управляет привязками для Firestore collectionReference.onSnapshot()
. Это ввело еще одно ограничение: я не могу напрямую запускать действие, когда документ добавляется, обновляется или удаляется. Это связано с тем, что VuexFire обрабатывает все эти изменения автоматически и не поддерживает привязку к этим событиям. Вместо этого я должен oop просмотреть все существующие сообщения и позвонить fetchUser()
. Я не включил это в приведенные выше примеры кода, потому что он не сильно отличается от snapshot.forEach()
. При необходимости я могу отказаться от этой библиотеки.
Итак, как лучше всего решить эту проблему?