Apollo client 3.5.5
Query that brings paginated comments:
const {
data: comments,
loading: commentsLoading,
fetchMore,
refetch,
subscribeToMore
} = useGetCommentsQuery({
variables: {
post_id: postId,
order_by: "desc",
limit: 40,
offset: 0
},
fetchPolicy: "cache-and-network"
});
GetCommentsQuery:
query GetComments(
$post_id: uuid
$limit: Int = 30
$offset: Int = 0
$order_by: order_by! = desc
) {
comment(
order_by: { created_at: $order_by }
where: { post: { id: { _eq: $post_id } }, parent_comment_id: { _is_null: true } }
limit: $limit
offset: $offset
) {
id
author_id
comment_liked
content
created_at
firebase_id
parent_comment_id
post_id
post {
id
}
author_profile {
id
is_staff
first_name
latest_login
profile_images(order_by: { order: asc }, limit: 1) {
...profileImages
}
}
comment_images {
...commentImages
}
comment_likes_aggregate {
aggregate {
count
}
nodes {
id
comment_id
profile_id
}
}
child_comments(order_by: { created_at: asc }) {
...childComment
}
}
}
Listener:
useEffect(() => {
subscribeToMore({
document: OnCommentAddedDocument,
variables: { post_id: postId, author_id: currentUser().uid },
updateQuery: (prev, { subscriptionData }) => {
if (Object.keys(prev || {}).length === 0) {
return null;
}
if (!subscriptionData.data || subscriptionData?.data?.comment?.length === 0) {
return prev;
}
const newComment = subscriptionData.data.comment[0];
const exists = findItemNested(prev.comment, newComment?.id, "child_comments");
if (exists) {
return prev;
}
return Object.assign({}, prev, {
comment: [...(prev.comment || []), newComment]
});
}
});
}, [postId]);
OnCommentAdded subscription:
subscription OnCommentAdded(
$post_id: uuid!
$order_by: order_by! = desc
$author_id: String!
) {
comment(
where: { post_id: { _eq: $post_id }, _not: { author_id: { _eq: $author_id } } }
order_by: { created_at: $order_by }
limit: 1
) {
id
author_id
comment_liked
content
created_at
firebase_id
parent_comment_id
post_id
post {
id
}
comment_images {
...commentImages
}
author_profile {
id
is_staff
first_name
latest_login
profile_images(order_by: { order: asc }, limit: 1) {
...profileImages
}
}
child_comments(order_by: { created_at: asc }) {
...childComment
}
comment_likes_aggregate {
aggregate {
count
}
nodes {
id
comment_id
profile_id
}
}
}
}
child_comments fragment:
fragment childComment on comment {
id
author_id
comment_liked
content
created_at
firebase_id
parent_comment_id
post_id
post {
id
}
author_profile {
id
is_staff
first_name
latest_login
profile_images(order_by: { order: asc }, limit: 1) {
...profileImages
}
}
comment_images {
...commentImages
}
comment_likes_aggregate {
aggregate {
count
}
nodes {
id
comment_id
profile_id
}
}
child_comments(order_by: { created_at: asc }) {
id
author_id
parent_comment_id
post {
id
}
post_id
firebase_id
comment_liked
created_at
comment_images {
...commentImages
}
author_profile {
id
is_staff
first_name
latest_login
profile_images(order_by: { order: asc }, limit: 1) {
...profileImages
}
}
content
comment_likes_aggregate {
aggregate {
count
}
nodes {
id
comment_id
profile_id
}
}
}
}
cache setup:
new InMemoryCache({
typePolicies: {
Query: {
fields: {
comment: offsetLimitPagination(["where"])
}
}
}
});
If the comment added from another user does not have a parent_id then the comment is being added on the comments list just fine. When a comment with a parent_id coming in, it's being added under the parent as it should but it's being added at the end of the list too.
Is there a way to update the cache without "touching" the ROOT_QUERY? Do i have to recursively iterate on every single comment child_comments (and it's child_comments, 2 levels deep) and inject the new comment on the appropriate parent comment child_comments instead of doing:
return Object.assign({}, prev, {
comment: [...(prev.comment || []), newComment]
});
Comments could be hundreds, iterating over won't be efficient and I was thinking if there's a better way or there's something totally wrong with my queries/cache.