0

I have a mutation where I append a comment to the first page (pages[0]). In my onMutate, I cancel any ongoing refetches (if we're not fetching a subsequent page) and then refetch in onSettled

Mutation:

    const createCommentMutation = useMutation({
    mutationFn: createComment,
    onMutate: async (variables) => {
        const { text, replyTo } = variables
        const cacheKey = replyTo ? ["postReplyComments", replyTo] : ["postComments", post._id]

        let wasFetchingFirstPage
        const query = queryClient.getQueryCache().find({ queryKey: cacheKey })
        if (query) {
            const observer = query.observers[0]
            const result = observer.getCurrentResult()

            wasFetchingFirstPage = result.isFetching && !result.isFetchingNextPage
        }

        wasFetchingFirstPage && queryClient.cancelQueries({ queryKey: cacheKey })

        const tempCommentId = uuidV4()
        const creatorData = {
            _id: userData._id,
            username: userData.username,
            profilePic: userData.profilePic,
        }
        const pendingComment = {
            _id: tempCommentId,
            createdAt: new Date().toISOString(),
        }

        queryClient.setQueryData(cacheKey, (prevData) => {
            return produce(prevData, (draft) => {
                const page = draft.pages[0]
                page.comments.unshift(pendingComment)

                if (wasFetchingFirstPage) page.pendingRefetch = true
            })
        })

        updateReply(null)
        textRef.current.value = ""

        return { pendingComment, cacheKey, wasFetchingFirstPage }
    },
    onSuccess: (data, variables, context) => {
        const { pendingComment, cacheKey } = context
        const { comment } = data
        // Optimistically replace comment in onsuccess
        queryClient.setQueryData(cacheKey, (prevData) => {
            return produce(prevData, (draft) => {
                const page = draft.pages[0]
                const pendingIndex = page.comments.findIndex(
                    (c) => c._id === pendingComment._id
                )
                const data = { ...comment, creator: pendingComment.creator }
                page.comments[pendingIndex] = data
            })
        })
    },
    onSettled: (_, __, ___, context) => {
        const { cacheKey, wasFetchingFirstPage } = context

        const refetchType = wasFetchingFirstPage ? "active" : "none"
        queryClient.invalidateQueries({ queryKey: cacheKey, refetchType })

        if (wasFetchingFirstPage) {
            queryClient.setQueryData(cacheKey, (prevData) => {
                return produce(prevData, (draft) => {
                    if (!prevData) return

                    const page = draft.pages[0]
                    page.pendingRefetch = false
                })
            })
        }
    },
})

The issue is when I call fetchNextPage() in my component, and whilst isFetchingNextPage is true, when I add a comment, and fetching completes, any comments added during this period are removed. My cursors are correct and pagination works as expected when I don't create any comments during this time.

I'm under the impression fetchNextPage() just appends a page to the pages array, however it is clearly modifying the first page. I can confirm invalidateQueries in onSettled is not the issue, as I've removed it and the issue persists. Also, I don't want to cancelQueries if we're fetching the next page.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.