Invalidate query cache when new chats come in

This commit is contained in:
Justin 2022-10-05 15:15:16 -04:00
parent 69d37a10fb
commit c41b71c76c
9 changed files with 51 additions and 37 deletions

View file

@ -1,7 +1,10 @@
import { InfiniteData } from '@tanstack/react-query';
import { getSettings } from 'soapbox/actions/settings'; import { getSettings } from 'soapbox/actions/settings';
import messages from 'soapbox/locales/messages'; import messages from 'soapbox/locales/messages';
import { ChatKeys } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client'; import { queryClient } from 'soapbox/queries/client';
import { updatePageItem, appendPageItem } from 'soapbox/utils/queries'; import { updatePageItem, appendPageItem, flattenPages, PaginatedResult } from 'soapbox/utils/queries';
import { play, soundCache } from 'soapbox/utils/sounds'; import { play, soundCache } from 'soapbox/utils/sounds';
import { connectStream } from '../stream'; import { connectStream } from '../stream';
@ -55,11 +58,22 @@ interface ChatPayload extends Omit<Chat, 'last_message'> {
const updateChat = (payload: ChatPayload) => { const updateChat = (payload: ChatPayload) => {
const { id: chatId, last_message: lastMessage } = payload; const { id: chatId, last_message: lastMessage } = payload;
queryClient.setQueryData<Chat>(['chats', 'chat', chatId], payload as any); const currentChats = flattenPages(queryClient.getQueryData<InfiniteData<PaginatedResult<unknown>>>(ChatKeys.chatSearch()));
updatePageItem<Chat>(['chats', 'search'], payload as any, (o, n) => o.id === n.id);
// Update the specific Chat query data.
queryClient.setQueryData<Chat>(ChatKeys.chat(chatId), payload as any);
if (currentChats?.find((chat: any) => chat.id === chatId)) {
// If the chat exists in the client, let's update it.
updatePageItem<Chat>(ChatKeys.chatSearch(), payload as any, (o, n) => o.id === n.id);
} else {
// If this is a brand-new chat, let's invalid the queries.
queryClient.invalidateQueries(ChatKeys.chatSearch());
}
if (lastMessage) { if (lastMessage) {
appendPageItem(['chats', 'messages', payload.id], lastMessage); // Update the Chat Messages query data.
appendPageItem(ChatKeys.chatMessages(payload.id), lastMessage);
} }
}; };

View file

@ -6,7 +6,7 @@ import { Stack, HStack, Card, Avatar, Text, Icon } from 'soapbox/components/ui';
import IconButton from 'soapbox/components/ui/icon-button/icon-button'; import IconButton from 'soapbox/components/ui/icon-button/icon-button';
import StatusCard from 'soapbox/features/status/components/card'; import StatusCard from 'soapbox/features/status/components/card';
import { useAppSelector } from 'soapbox/hooks'; import { useAppSelector } from 'soapbox/hooks';
import { adKeys } from 'soapbox/queries/ads'; import { AdKeys } from 'soapbox/queries/ads';
import type { Card as CardEntity } from 'soapbox/types/entities'; import type { Card as CardEntity } from 'soapbox/types/entities';
@ -30,7 +30,7 @@ const Ad: React.FC<IAd> = ({ card, impression, expires }) => {
/** Invalidate query cache for ads. */ /** Invalidate query cache for ads. */
const bustCache = (): void => { const bustCache = (): void => {
queryClient.invalidateQueries(adKeys.ads); queryClient.invalidateQueries(AdKeys.ads);
}; };
/** Toggle the info box on click. */ /** Toggle the info box on click. */
@ -113,7 +113,7 @@ const Ad: React.FC<IAd> = ({ card, impression, expires }) => {
</Stack> </Stack>
</HStack> </HStack>
<StatusCard card={card} onOpenMedia={() => {}} horizontal /> <StatusCard card={card} onOpenMedia={() => { }} horizontal />
</Stack> </Stack>
</Card> </Card>

View file

@ -16,7 +16,7 @@ import Bundle from 'soapbox/features/ui/components/bundle';
import { MediaGallery } from 'soapbox/features/ui/util/async-components'; import { MediaGallery } from 'soapbox/features/ui/util/async-components';
import { useAppSelector, useAppDispatch, useOwnAccount } from 'soapbox/hooks'; import { useAppSelector, useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import { normalizeAccount } from 'soapbox/normalizers'; import { normalizeAccount } from 'soapbox/normalizers';
import { chatKeys, IChat, IChatMessage, useChatActions, useChatMessages } from 'soapbox/queries/chats'; import { ChatKeys, IChat, IChatMessage, useChatActions, useChatMessages } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client'; import { queryClient } from 'soapbox/queries/client';
import { stripHTML } from 'soapbox/utils/html'; import { stripHTML } from 'soapbox/utils/html';
import { onlyEmoji } from 'soapbox/utils/rich_content'; import { onlyEmoji } from 'soapbox/utils/rich_content';
@ -96,7 +96,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat, autosize }) => {
const handleDeleteMessage = useMutation((chatMessageId: string) => deleteChatMessage(chatMessageId), { const handleDeleteMessage = useMutation((chatMessageId: string) => deleteChatMessage(chatMessageId), {
onSettled: () => { onSettled: () => {
queryClient.invalidateQueries(chatKeys.chatMessages(chat.id)); queryClient.invalidateQueries(ChatKeys.chatMessages(chat.id));
}, },
}); });

View file

@ -11,7 +11,7 @@ import { useChats } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client'; import { queryClient } from 'soapbox/queries/client';
import useAccountSearch from 'soapbox/queries/search'; import useAccountSearch from 'soapbox/queries/search';
import { chatKeys } from '../../../../queries/chats'; import { ChatKeys } from '../../../../queries/chats';
import ChatPaneHeader from '../chat-pane-header'; import ChatPaneHeader from '../chat-pane-header';
import { Pane } from '../ui'; import { Pane } from '../ui';
@ -48,7 +48,7 @@ const ChatSearch = () => {
}, },
onSuccess: (response) => { onSuccess: (response) => {
setChat(response.data); setChat(response.data);
queryClient.invalidateQueries(chatKeys.chatSearch()); queryClient.invalidateQueries(ChatKeys.chatSearch());
}, },
}); });

View file

@ -8,7 +8,7 @@ import { HStack, IconButton, Stack, Text, Textarea } from 'soapbox/components/ui
import UploadProgress from 'soapbox/components/upload-progress'; import UploadProgress from 'soapbox/components/upload-progress';
import UploadButton from 'soapbox/features/compose/components/upload_button'; import UploadButton from 'soapbox/features/compose/components/upload_button';
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import { chatKeys, IChat, useChatActions } from 'soapbox/queries/chats'; import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client'; import { queryClient } from 'soapbox/queries/client';
import { truncateFilename } from 'soapbox/utils/media'; import { truncateFilename } from 'soapbox/utils/media';
@ -91,7 +91,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, autosize, inputRef, className })
}, },
// Always refetch after error or success: // Always refetch after error or success:
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries(chatKeys.chatMessages(chat.id)); queryClient.invalidateQueries(ChatKeys.chatMessages(chat.id));
}, },
}); });

View file

@ -4,15 +4,15 @@ import { Ad, getProvider } from 'soapbox/features/ads/providers';
import { useAppDispatch } from 'soapbox/hooks'; import { useAppDispatch } from 'soapbox/hooks';
import { isExpired } from 'soapbox/utils/ads'; import { isExpired } from 'soapbox/utils/ads';
const adKeys = { const AdKeys = {
ads: ['ads'] as const, ads: ['ads'] as const,
}; };
function useAds() { function useAds() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const getAds = async() => { const getAds = async () => {
return dispatch(async(_, getState) => { return dispatch(async (_, getState) => {
const provider = await getProvider(getState); const provider = await getProvider(getState);
if (provider) { if (provider) {
return provider.getAds(getState); return provider.getAds(getState);
@ -22,7 +22,7 @@ function useAds() {
}); });
}; };
const result = useQuery<Ad[]>(adKeys.ads, getAds, { const result = useQuery<Ad[]>(AdKeys.ads, getAds, {
placeholderData: [], placeholderData: [],
}); });
@ -35,4 +35,4 @@ function useAds() {
}; };
} }
export { useAds as default, adKeys }; export { useAds as default, AdKeys };

View file

@ -52,7 +52,7 @@ export interface IChatSilence {
target_account_id: number target_account_id: number
} }
const chatKeys = { const ChatKeys = {
chat: (chatId?: string) => ['chats', 'chat', chatId] as const, chat: (chatId?: string) => ['chats', 'chat', chatId] as const,
chatMessages: (chatId: string) => ['chats', 'messages', chatId] as const, chatMessages: (chatId: string) => ['chats', 'messages', chatId] as const,
chatSearch: (searchQuery?: string) => searchQuery ? ['chats', 'search', searchQuery] : ['chats', 'search'] as const, chatSearch: (searchQuery?: string) => searchQuery ? ['chats', 'search', searchQuery] : ['chats', 'search'] as const,
@ -81,7 +81,7 @@ const useChatMessages = (chatId: string) => {
}; };
}; };
const queryInfo = useInfiniteQuery(chatKeys.chatMessages(chatId), ({ pageParam }) => getChatMessages(chatId, pageParam), { const queryInfo = useInfiniteQuery(ChatKeys.chatMessages(chatId), ({ pageParam }) => getChatMessages(chatId, pageParam), {
getNextPageParam: (config) => { getNextPageParam: (config) => {
if (config.hasMore) { if (config.hasMore) {
return { link: config.link }; return { link: config.link };
@ -91,7 +91,7 @@ const useChatMessages = (chatId: string) => {
}, },
}); });
const data = flattenPages(queryInfo); const data = flattenPages(queryInfo.data);
return { return {
...queryInfo, ...queryInfo,
@ -133,7 +133,7 @@ const useChats = (search?: string) => {
}; };
}; };
const queryInfo = useInfiniteQuery(chatKeys.chatSearch(search), ({ pageParam }) => getChats(pageParam), { const queryInfo = useInfiniteQuery(ChatKeys.chatSearch(search), ({ pageParam }) => getChats(pageParam), {
keepPreviousData: true, keepPreviousData: true,
getNextPageParam: (config) => { getNextPageParam: (config) => {
if (config.hasMore) { if (config.hasMore) {
@ -144,7 +144,7 @@ const useChats = (search?: string) => {
}, },
}); });
const data = flattenPages(queryInfo); const data = flattenPages(queryInfo.data);
const chatsQuery = { const chatsQuery = {
...queryInfo, ...queryInfo,
@ -171,7 +171,7 @@ const useChat = (chatId?: string) => {
} }
}; };
const chat = useQuery<IChat | undefined>(chatKeys.chat(chatId), getChat); const chat = useQuery<IChat | undefined>(ChatKeys.chat(chatId), getChat);
return { ...actions, chat }; return { ...actions, chat };
}; };
@ -195,8 +195,8 @@ const useChatActions = (chatId: string) => {
const acceptChat = useMutation(() => api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/accept`), { const acceptChat = useMutation(() => api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/accept`), {
onSuccess(response) { onSuccess(response) {
setChat(response.data); setChat(response.data);
queryClient.invalidateQueries(chatKeys.chatMessages(chatId)); queryClient.invalidateQueries(ChatKeys.chatMessages(chatId));
queryClient.invalidateQueries(chatKeys.chatSearch()); queryClient.invalidateQueries(ChatKeys.chatSearch());
}, },
}); });
@ -204,8 +204,8 @@ const useChatActions = (chatId: string) => {
onSuccess(response) { onSuccess(response) {
setChat(null); setChat(null);
setEditing(false); setEditing(false);
queryClient.invalidateQueries(chatKeys.chatMessages(chatId)); queryClient.invalidateQueries(ChatKeys.chatMessages(chatId));
queryClient.invalidateQueries(chatKeys.chatSearch()); queryClient.invalidateQueries(ChatKeys.chatSearch());
}, },
}); });
@ -221,7 +221,7 @@ const useChatSilences = () => {
return data; return data;
}; };
return useQuery<IChatSilence[]>(chatKeys.chatSilences, getChatSilences, { return useQuery<IChatSilence[]>(ChatKeys.chatSilences, getChatSilences, {
placeholderData: [], placeholderData: [],
}); });
}; };
@ -260,7 +260,7 @@ const useChatSilence = (chat: IChat | null) => {
api.post(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`) api.post(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`)
.then(() => { .then(() => {
dispatch(snackbar.success('Successfully silenced this chat.')); dispatch(snackbar.success('Successfully silenced this chat.'));
queryClient.invalidateQueries(chatKeys.chatSilences); queryClient.invalidateQueries(ChatKeys.chatSilences);
}) })
.catch(() => { .catch(() => {
dispatch(snackbar.error('Something went wrong trying to silence this chat. Please try again.')); dispatch(snackbar.error('Something went wrong trying to silence this chat. Please try again.'));
@ -274,7 +274,7 @@ const useChatSilence = (chat: IChat | null) => {
api.delete(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`) api.delete(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`)
.then(() => { .then(() => {
dispatch(snackbar.success('Successfully unsilenced this chat.')); dispatch(snackbar.success('Successfully unsilenced this chat.'));
queryClient.invalidateQueries(chatKeys.chatSilences); queryClient.invalidateQueries(ChatKeys.chatSilences);
}) })
.catch(() => { .catch(() => {
dispatch(snackbar.error('Something went wrong trying to unsilence this chat. Please try again.')); dispatch(snackbar.error('Something went wrong trying to unsilence this chat. Please try again.'));
@ -285,4 +285,4 @@ const useChatSilence = (chat: IChat | null) => {
return { isSilenced, handleSilence, fetchChatSilence }; return { isSilenced, handleSilence, fetchChatSilence };
}; };
export { chatKeys, useChat, useChatActions, useChats, useChatMessages, useChatSilences, useChatSilence }; export { ChatKeys, useChat, useChatActions, useChats, useChatMessages, useChatSilences, useChatSilence };

View file

@ -32,7 +32,7 @@ type PageParam = {
link?: string link?: string
} }
const suggestionKeys = { const SuggestionKeys = {
suggestions: ['suggestions'] as const, suggestions: ['suggestions'] as const,
}; };
@ -94,7 +94,7 @@ const useSuggestions = () => {
}; };
const result = useInfiniteQuery( const result = useInfiniteQuery(
suggestionKeys.suggestions, SuggestionKeys.suggestions,
({ pageParam }: any) => getSuggestions(pageParam), ({ pageParam }: any) => getSuggestions(pageParam),
{ {
keepPreviousData: true, keepPreviousData: true,
@ -123,7 +123,7 @@ const useDismissSuggestion = () => {
return useMutation((accountId: string) => api.delete(`/api/v1/suggestions/${accountId}`), { return useMutation((accountId: string) => api.delete(`/api/v1/suggestions/${accountId}`), {
onMutate(accountId: string) { onMutate(accountId: string) {
removePageItem(suggestionKeys.suggestions, accountId, (o: any, n: any) => o.account_id === n); removePageItem(SuggestionKeys.suggestions, accountId, (o: any, n: any) => o.account_id === n);
}, },
}); });
}; };

View file

@ -9,8 +9,8 @@ export interface PaginatedResult<T> {
} }
/** Flatten paginated results into a single array. */ /** Flatten paginated results into a single array. */
const flattenPages = <T>(queryInfo: UseInfiniteQueryResult<PaginatedResult<T>>) => { const flattenPages = <T>(queryData: UseInfiniteQueryResult<PaginatedResult<T>>['data']) => {
return queryInfo.data?.pages.reduce<T[]>( return queryData?.pages.reduce<T[]>(
(prev: T[], curr) => [...curr.result, ...prev], (prev: T[], curr) => [...curr.result, ...prev],
[], [],
); );