T
TanStack2y ago
sensitive-blue

Any guidance / examples on react-query + handling live websocket events?

Hey react-query community, we're working on an application that will have a live-updating list of items. We are currently using react-query alongside cursor-based pagination + infinite queries to fetch data. However, we want to also integrate with websocket events (new item, delete item, modify item, etc.) so that we don't need to constantly refetch (polling). We want to be cautious to not produce bugs with duplicate items, missing items, or malformed data in general. Is there any guidance or good code examples for this scenario? Thank you! :reactquery:
17 Replies
rare-sapphire
rare-sapphire2y ago
Using WebSockets with React Query
A step-by-step guide on how to make real-time notifications work with react-query
sensitive-blue
sensitive-blueOP2y ago
Hi TkDodo, I have read this in the past and it's served as a good base, but I am curious if you have advice on handling duplicates / missing data / malformed data For example (shown in the attached image) 1. Initial infinite query gets the first 5 tokens and stores it in the cache 2. Process websocket event and add Token 6 manually to the cache 3. Problem: When fetching the next page, there will be a duplicate Token 6
No description
sensitive-blue
sensitive-blueOP2y ago
I'm sure this is a common consideration for other live applications (chat / marketplaces / etc.) yet I haven't found good guidance or examples on best practices for this yet
rare-sapphire
rare-sapphire2y ago
If you add 6 to the end of page one, the getNextPageParam for page2 should point to 7, no?
sensitive-blue
sensitive-blueOP2y ago
By default getNextPageParam would be Token 6 because the first call got the first 5 tokens. Then we would manually update the cache and add the Token 6 from the websocket event. So are you suggesting the best way is I should manually update nextPageParam after I manually update the cache with data from web socket events?
rare-sapphire
rare-sapphire2y ago
getNextPageParam will be evaluated when you call fetchNextPage, so it should yield 6
sensitive-blue
sensitive-blueOP2y ago
Right but: - First query call gets first page of Tokens 1 - 6 with nextPageParam as Token 6 - Handle websocket event to add Token 6 to the cache - If I call fetchNextPage, then it will use nextPageParam of Token 6 which means I will get duplicates
rare-sapphire
rare-sapphire2y ago
if you add token 6 to the cache, it will look like:
total: 100,
nextCursor: 7
total: 100,
nextCursor: 7
and then when fetchNextPage is called, it will read the nextCursor and fetch 7
sensitive-blue
sensitive-blueOP2y ago
Hmm, how would this be the case by default though if the first query call has a cursor of Token 6? How is it aware of me adding Token 6 to the cache and to know to update the next cursor to 7? since I'm using
initialPageParam: "",
getNextPageParam: (prevData) => {
if (prevData.cursor.next) {
return prevData.cursor.next;
}
},
initialPageParam: "",
getNextPageParam: (prevData) => {
if (prevData.cursor.next) {
return prevData.cursor.next;
}
},
rare-sapphire
rare-sapphire2y ago
Have you actually tried it?
sensitive-blue
sensitive-blueOP2y ago
I have not yet but I can’t reason how it would work - unless I’m missing some understanding?
rare-sapphire
rare-sapphire2y ago
When you update the cached value with setQueryData, the next time getNextPageParam is called (which happens when you call fetchNextPage), it will see the latest value (6) and will give you the correct next pointer (7), then the queryFn is called with that pageParam
sensitive-blue
sensitive-blueOP2y ago
When I call setQueryData though I would have to manually update the pageParams with the new proper cursor value (alongside adding the new item into the array) right? aka
const newPages = [...oldPagesArray.pages[0], "Token 6"]

queryClient.setQueryData<InfiniteData<ContractAssets, unknown>>(
["tokens"],
(data) => ({
pages: newPages,
pageParams: newPageParams, // new page params with updated cursor here
}),
);
const newPages = [...oldPagesArray.pages[0], "Token 6"]

queryClient.setQueryData<InfiniteData<ContractAssets, unknown>>(
["tokens"],
(data) => ({
pages: newPages,
pageParams: newPageParams, // new page params with updated cursor here
}),
);
rare-sapphire
rare-sapphire2y ago
No, this is the pageParam that was used to fetch this page. It's not relevant for the next page, unless you use this in getNextPageParam
sensitive-blue
sensitive-blueOP2y ago
The main issue I see is that the cursors are calculated and returned by the backend. And since the items can be sorted in different ways, it’s not always as simple as just incrementing the number. The cursors are strings like “dXNlcjpVMEc5V0ZYTlo=“
sensitive-blue
sensitive-blueOP2y ago
Slack API
Paginating through collections
How to navigate through lists of conversations, users, and so on -- using cursors or otherwise.
sensitive-blue
sensitive-blueOP2y ago
Sorry let me know if direct mentions are not allowed but wanted to just bump this @TkDodo 🔮

Did you find this page helpful?