Skip to content

Commit 5943b3e

Browse files
committed
queue nested comments without a parent, retry on the next poll
1 parent 3d8fd6f commit 5943b3e

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

components/use-live-comments.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useQuery, useApolloClient } from '@apollo/client'
22
import { SSR } from '../lib/constants'
33
import { GET_NEW_COMMENTS, COMMENT_WITH_NEW } from '../fragments/comments'
44
import { ITEM_FULL } from '../fragments/items'
5-
import { useCallback, useEffect, useState } from 'react'
5+
import { useCallback, useEffect, useState, useRef } from 'react'
66
import styles from './comment.module.css'
77

88
const POLL_INTERVAL = 1000 * 10 // 10 seconds
@@ -25,6 +25,7 @@ function commentUpdateFragment (client, id, fn) {
2525
export default function useLiveComments (rootId, after, sort) {
2626
const client = useApolloClient()
2727
const [latest, setLatest] = useState(after)
28+
const queuedCommentsRef = useRef([])
2829

2930
const { data } = useQuery(GET_NEW_COMMENTS, SSR
3031
? {}
@@ -36,15 +37,22 @@ export default function useLiveComments (rootId, after, sort) {
3637
useEffect(() => {
3738
if (!data?.newComments) return
3839

39-
cacheNewComments(client, rootId, data.newComments.comments, sort)
40-
// check new comments created after the latest new comment
40+
// live comments can be orphans if the parent comment is not in the cache
41+
// queue them up and retry later, when the parent decides they want the children.
42+
const allComments = [...queuedCommentsRef.current, ...data.newComments.comments]
43+
const { queuedComments } = cacheNewComments(client, rootId, allComments, sort)
44+
45+
// keep the queued comments in the ref for the next poll
46+
queuedCommentsRef.current = queuedComments
47+
48+
// update latest timestamp to the latest comment created at
4149
setLatest(prevLatest => getLatestCommentCreatedAt(data.newComments.comments, prevLatest))
4250
}, [data, client, rootId, sort])
4351
}
4452

4553
function cacheNewComments (client, rootId, newComments, sort) {
46-
// update the item with the new comments
47-
// if the comment is a top level comment, update the item
54+
const queuedComments = []
55+
4856
for (const newComment of newComments) {
4957
console.log('newComment', newComment)
5058
const { parentId } = newComment
@@ -58,14 +66,28 @@ function cacheNewComments (client, rootId, newComments, sort) {
5866
return { item: mergeNewComment(data?.item, newComment) }
5967
})
6068
} else {
61-
// if the comment is a reply, update the parent comment
62-
console.log('reply', parentId)
63-
commentUpdateFragment(client, parentId, (data) => {
64-
if (!data) return data
65-
return mergeNewComment(data, newComment)
69+
// check if parent exists in cache before attempting update
70+
const parentExists = client.cache.readFragment({
71+
id: `Item:${parentId}`,
72+
fragment: COMMENT_WITH_NEW,
73+
fragmentName: 'CommentWithNew'
6674
})
75+
76+
if (parentExists) {
77+
// if the comment is a reply, update the parent comment
78+
console.log('reply', parentId)
79+
commentUpdateFragment(client, parentId, (data) => {
80+
if (!data) return data
81+
return mergeNewComment(data, newComment)
82+
})
83+
} else {
84+
// parent not in cache, queue for retry
85+
queuedComments.push(newComment)
86+
}
6787
}
6888
}
89+
90+
return { queuedComments }
6991
}
7092

7193
// merge new comment into item's newComments

0 commit comments

Comments
 (0)