Llabe
Llabe•10mo ago

Pagination + Optimistic updates

I have two questions, one exclusively related to pagination and another with combines pagination with optimistic updates. Basically I am building a chat in my applicatin so team members can talk to each other. 1) In the code below you can see my convex function to return members form a project which should go to the chat members list. But I have to populate the user data field so thats why I have the promise all, when I try to implement it with pagination using the documentation in the convex web I get an error as I can't iterate a PaginatedREsult (I belive its call like that), and if I access the data then the paginated query throws an error: export const getMembers = query({ args: { projectId: v.id('projects'), }, handler: async (ctx, args) => { const access = await accessToProject( ctx, args.projectId, 'juanillaberia2002@gmail.com' ); if (!access) return []; const projectMembers = await ctx.db .query('project_members') .withIndex('by_projectId', q => q.eq('projectId', args.projectId)) .collect(); // const projectMembers = await ctx.db // .query('project_members') // .withIndex('by_projectId', q => q.eq('projectId', args.projectId)) // .paginate(args.paginationOpts); return await Promise.all( projectMembers.map(async member => { const userData = await ctx.db.get(member.userId); return { ...userData, role: member.role, }; }) ); }, }); 2) And second, is it possible to implement optimistic updates and also paginate messages? I successfully implemented the optimistic updates, but I am not quite sure how to add the pagination (because of the question 1 and also if they go well together or their are meant to be separated features) as messages contain the userId who sent it and I need to query for the image and the name. Thank you so much for your time! 🙂
9 Replies
lee
lee•10mo ago
for 2) there's this https://docs.convex.dev/api/modules/react#optimisticallyupdatevalueinpaginatedquery for (1) i think @Michal Srb can help 🙂
Module: react | Convex Developer Hub
Tools to integrate Convex into React applications.
Michal Srb
Michal Srb•10mo ago
1.
return {...projectMembers, page: await Promise.all(
projectMembers.page.map(async member => {
const userData = await ctx.db.get(member.userId);
return {
...userData,
role: member.role,
};
})
)};
return {...projectMembers, page: await Promise.all(
projectMembers.page.map(async member => {
const userData = await ctx.db.get(member.userId);
return {
...userData,
role: member.role,
};
})
)};
I'll make sure we add this to our docs! 2. To add to @lee :
import {
optimisticallyUpdateValueInPaginatedQuery,
} from "convex/react";
import {
optimisticallyUpdateValueInPaginatedQuery,
} from "convex/react";
Llabe
LlabeOP•10mo ago
Thanks you @lee and @Michal Srb . I'll try to implement it now I was able to implement the pagination. But the optimistic updates in combination with the pagination is not working for me. Its now throwing any error but the mmessages are not being added with the optimistic. My implementation: //get messages function export const getMessages = query({ args: { projectId: v.id('projects'), paginationOpts: paginationOptsValidator, }, handler: async (ctx, args) => { const messages = await ctx.db .query('messages') .withIndex('by_projectId_time', q => q.eq('projectId', args.projectId)) .order('desc') .paginate(args.paginationOpts); return { ...messages, page: await Promise.all( messages.page.map(async msg => { const userData = await ctx.db.get(msg.sendBy); return { ...msg, sendBy: { ...userData, }, }; }) ), }; }, }); //This is the conversation page: const Conversation = ({ projectId }: { projectId: Id<'projects'> }) => { const { results, loadMore, status } = usePaginatedQuery( api.messages.getMessages, { projectId }, { initialNumItems: 1, } ); if (status === 'LoadingFirstPage') return ( <ul className='flex flex-col flex-1 gap-6 w-full'> <MessageLoader /> <MessageLoader /> <MessageLoader /> <MessageLoader /> <MessageLoader /> </ul> ); console.log(results); return ( <ul className='flex-1 w-full overflow-y-auto'> <button onClick={() => loadMore(1)}>MORE</button> {results.length > 0 ? ( results .sort((a, b) => a._creationTime - b._creationTime) .map(msg => ( <Message messageData={msg} senderData={msg.sendBy} isFirstInGroup={true} /> )) ) : ( <p className='flex justify-center items-center h-full text-sm text-center text-text-2'> No messages yet </p> )} </ul> ); }; export default Conversation; //This is where I send the messages const ChatInput = ({ projectId, userEmail, }: { projectId: Id<'projects'>; userEmail: string; }) => { //Message value const [message, setMessage] = useState(''); const sendMessage = useMutation( api.messages.sendMessage ).withOptimisticUpdate((localStore, mutationArg) => { optimisticallyUpdateValueInPaginatedQuery( localStore, api.messages.getMessages, { projectId }, crrVal => { const crrUser = localStore.getQuery(api.users.getUserByEmail, { email: userEmail, }); const newMessage = { _id: crypto.randomUUID() as Id<'messages'>, _creationTime: Date.now(), projectId, data: mutationArg.data, sendBy: crrUser, }; return { ...crrVal, newMessage, }; } ); }); const handleSendMessage = async ( projectId: Id<'projects'>, newMessageText: string ) => { await sendMessage({ projectId: projectId, data: newMessageText }); }; return ( ... ); }; export default ChatInput; Sorry for all the messages. Basiccaly I am able to paginate when I click the btn I get more messages all good, but the optimistic is taking the 'regular time', I am probably doing something wrong
Michal Srb
Michal Srb•10mo ago
Oh, rereading the doc for optimisticallyUpdateValueInPaginatedQuery, it's only useful for updating the existing pages, whereas you want to add a new item into the query. I'll try to see if normal withOptimisticUpdate will work This is a bit more involved, I'll file this as a feature request. For now I'd stick to using React state and showing the "in-flight" message outside the paginated query results. When the paginated query results change you can reset the React state (within the render pass, so that the "in-flight" message and the message from the server aren't both rendered at the same time).
Llabe
LlabeOP•10mo ago
Okey perfect, no worries. I'll try to make it work. Thanks! @Michal Srb In your opinion, if I can only choose one of the convex feature, should it be the pagination or the optimistic updates?
Michal Srb
Michal Srb•10mo ago
It really depends on your app. Probably pagination, since that usually becomes a requirement once your data grows.
Llabe
LlabeOP•10mo ago
I was thinking the same. The optimistic, I may be able to implemented in the front end.
Starlord
Starlord•5d ago
hey, seems its not possible also to delete form paginated query with optimistic update
ballingt
ballingt•4d ago
@Starlord not possible as it https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L533 has a bug? What do you expect, and what is happening?