admin管理员组

文章数量:1122832

I fetch chats initially, using useQuery, and then any subsequent updates to chats such as new chats are handled by my realtime socket handlers.

ChatList.js:

const { data, error, isFetching, isLoading } = useQuery({
    queryKey: ["chats"],
    queryFn: fetchChats,
    staleTime: Infinity,
})

In my SocketContext.js, whenever I receieve a new chat, I add it to the cache. If the query is initially fetching for the first time, the cache is obviously empty at this point. I check whether this existing chat is already in the cache, and if not I add it to the cache.

socket.on("new_chat", (data) => {
     const {chatData} = data
     queryClient.setQueryData(["chats"], (prevChats = []) => {
            const existingChat = prevChats?.find((c) => c._id === chatData._id)
            // Add to cache if not already there
            if (!existingChat) return [chatData, ...prevChats]

            const filteredChats = prevChats.filter((c) => c._id !== existingChat._id)
            const updatedChat = { ...existingChat, latestMessage: message }

            return [updatedChat, ...filteredChats]
      }) })

The problem I have is that if a chat is added to the cache whilst initially fetching, it is then overwritten when useQuery finishes fetching. This data from useQuery may not include this new chat. I tried to call invalidateQueries given I receieve a chat in realtime and isFetching for the chats is true, however this is pointless as the cache is empty at this point so invalidateQueries does nothing.

One solution I tried was storing realtime updates in a queue whilst isFetching is true for the chats query and then merge the updates once fetching completes, however this seems tedious especially considering onSuccess was removed from the useQuery hook. Any ways I could potentially handle this?

I fetch chats initially, using useQuery, and then any subsequent updates to chats such as new chats are handled by my realtime socket handlers.

ChatList.js:

const { data, error, isFetching, isLoading } = useQuery({
    queryKey: ["chats"],
    queryFn: fetchChats,
    staleTime: Infinity,
})

In my SocketContext.js, whenever I receieve a new chat, I add it to the cache. If the query is initially fetching for the first time, the cache is obviously empty at this point. I check whether this existing chat is already in the cache, and if not I add it to the cache.

socket.on("new_chat", (data) => {
     const {chatData} = data
     queryClient.setQueryData(["chats"], (prevChats = []) => {
            const existingChat = prevChats?.find((c) => c._id === chatData._id)
            // Add to cache if not already there
            if (!existingChat) return [chatData, ...prevChats]

            const filteredChats = prevChats.filter((c) => c._id !== existingChat._id)
            const updatedChat = { ...existingChat, latestMessage: message }

            return [updatedChat, ...filteredChats]
      }) })

The problem I have is that if a chat is added to the cache whilst initially fetching, it is then overwritten when useQuery finishes fetching. This data from useQuery may not include this new chat. I tried to call invalidateQueries given I receieve a chat in realtime and isFetching for the chats is true, however this is pointless as the cache is empty at this point so invalidateQueries does nothing.

One solution I tried was storing realtime updates in a queue whilst isFetching is true for the chats query and then merge the updates once fetching completes, however this seems tedious especially considering onSuccess was removed from the useQuery hook. Any ways I could potentially handle this?

Share Improve this question edited Nov 22, 2024 at 20:37 Max adam asked Nov 22, 2024 at 16:06 Max adamMax adam 1056 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

You need to do Queue Realtime Updates

Store new chats in a queue while fetching:

const newChatsQueue = useRef([]);

socket.on("new_chat", (data) => {
    const { chatData } = data;
    if (isFetching) {
        newChatsQueue.current.push(chatData);
    } else {
        updateChats(chatData);
    }
});

const updateChats = (chatData) => {
    queryClient.setQueryData(["chats"], (prevChats = []) => {
        const exists = prevChats.some((c) => c._id === chatData._id);
        if (!exists) return [chatData, ...prevChats];
        return prevChats;
    });
};

Apply the queue after fetching completes:

useEffect(() => {
    if (!isFetching && newChatsQueue.current.length) {
        queryClient.setQueryData(["chats"], (prevChats = []) => [
            ...newChatsQueue.current,
            ...prevChats,
        ]);
        newChatsQueue.current = [];
    }
}, [isFetching]);

This avoids overwriting realtime updates during the initial fetch.

本文标签: reactjsHandling realtime socket events whilst initially fetching queryStack Overflow