# #reactjs #firebase #google-cloud-firestore #react-hooks #zustand
Вопрос:
всякий раз, когда я получаю новое сообщение из своей коллекции сообщений через onSnapshot, мои входящие сообщения не отправляются повторно.
Я могу подтвердить, что новое сообщение определенно хранится в a useRef
, как я вижу его в инструментах разработки, однако сообщение не попадает в DOM.
Я следовал zustand's
документации, в которой объясняется, что рекомендуется использовать ссылку и их методы подписки для повторных изменений состояния: https://github.com/pmndrs/zustand#transient-updates-for-often-occuring-state-changes
Кто-нибудь может понять, в чем я, возможно, ошибаюсь?
Страница сообщений, на которой отображаются разговоры и обновления в реальном времени:
import { useState, useEffect, useRef } from "react";
import "./Messages.scss";
import { db } from "../../firebase";
import { Message, Conversation } from "../../Interfaces/Interfaces";
import MessagesHeader from "./Components/MessagesHeader/MessagesHeader";
import MessagesConversations from "./Components/MessagesConversations/MessagesConversations";
import create from "zustand";
import authStore from "../../Global/AuthState/AuthStore";
interface ConversationsStore {
conversations: Array<Conversation>;
setConversations: (newConversations: Array<Conversation>) => void;
}
const conversationsStore = create<ConversationsStore>((set) => ({
conversations: [],
setConversations: (newConversations: Array<Conversation>) =>
set({ conversations: newConversations }),
}));
function Messages() {
const currentUser = authStore((state) => state.currentUser);
const [subToUpdates, setSubToUpdates] = useState<boolean>(false);
const [initialDone, setInitialDone] = useState<boolean>(false);
//create the initial conversations ref
const conversationsRef = useRef<Array<Conversation>>(
conversationsStore.getState().conversations
);
const conversations = conversationsStore((state) => state.conversations);
const setConversations = conversationsStore(
(state) => state.setConversations
);
//zustand's recommended subscribe useEffect to re-render whenever a new conversation enters the db
useEffect(
() =>
conversationsStore.subscribe(
(state) => (conversationsRef.current = state.conversations)
),
[]
);
//get the current conversations that the user is in
useEffect(() => {
if (currentUser) {
let initialConversations: Array<Conversation> = [];
const conversationsRef = db.collection("conversations");
const getInitialConversations = async () => {
const conversationsSnapshot = await conversationsRef
.where("users", "array-contains", currentUser.uid)
.orderBy("latestMessageDate", "desc")
.get();
conversationsSnapshot.forEach((doc) => {
let tempConversation: Conversation = doc.data() as Conversation;
tempConversation.conversationId = doc.id;
initialConversations.push(tempConversation);
setConversations(initialConversations);
});
};
getInitialConversations().then(() => setSubToUpdates(true));
}
}, [currentUser]);
//after the initial load, listen to changes in the firestore collection
useEffect(() => {
if (subToUpdates amp;amp; currentUser amp;amp; !initialDone) {
setInitialDone(true);
} else if (subToUpdates amp;amp; currentUser amp;amp; initialDone) {
const conversationsRef = db.collection("conversations");
return conversationsRef
.where("users", "array-contains", currentUser.uid)
.orderBy("latestMessageDate", "desc")
.limit(1)
.onSnapshot((querySnapshot) => {
console.log("new conversation found");
querySnapshot.forEach((doc) => {
{
/*
let tempConversations = conversations?.filter(
(currentConversation) =>
currentConversation.conversationId == doc.id
);
*/
}
let tempConversations = conversations;
let tempConversation: Conversation = doc.data() as Conversation;
tempConversation.conversationId = doc.id;
tempConversations?.push(tempConversation);
setConversations(tempConversations);
});
});
}
}, [subToUpdates, initialDone]);
return (
<div className="messages">
{conversations.length > 0 amp;amp;
conversations.map((conversation, index) => (
<h4 key={index}>{conversation.latestMessage.message}</h4>
))}
<MessagesHeader />
<MessagesConversations
conversations={conversationsRef.current}
filterByUnread={false}
/>
</div>
);
}
export default Messages;
Контейнер «Входящие разговоры», который отображает разговоры и показывает их:
import React from "react";
import "./MessagesConversations.scss";
import MessagesConversationsConversation from "./Components/MessagesConversationsConversation/MessagesConversationsConversation";
import { Conversation } from "../../../../Interfaces/Interfaces";
interface Props {
conversations: Array<Conversation> | undefined;
filterByUnread: boolean;
}
function MessagesConversations({ conversations, filterByUnread }: Props) {
return (
<div className="messagesConversations">
{conversations !== undefined amp;amp;
(conversations?.length > 0 ? (
conversations.map((conversation) => (
<MessagesConversationsConversation
conversation={conversation}
key={`conversation__${conversation.conversationId}`}
/>
))
) : (
<h4>No messages</h4>
))}
</div>
);
}
export default MessagesConversations;