@@ -2,7 +2,7 @@ import { useQuery, useApolloClient } from '@apollo/client'
2
2
import { SSR } from '../lib/constants'
3
3
import { GET_NEW_COMMENTS , COMMENT_WITH_NEW } from '../fragments/comments'
4
4
import { ITEM_FULL } from '../fragments/items'
5
- import { useCallback , useEffect , useState } from 'react'
5
+ import { useCallback , useEffect , useState , useRef } from 'react'
6
6
import styles from './comment.module.css'
7
7
8
8
const POLL_INTERVAL = 1000 * 10 // 10 seconds
@@ -25,6 +25,7 @@ function commentUpdateFragment (client, id, fn) {
25
25
export default function useLiveComments ( rootId , after , sort ) {
26
26
const client = useApolloClient ( )
27
27
const [ latest , setLatest ] = useState ( after )
28
+ const queuedCommentsRef = useRef ( [ ] )
28
29
29
30
const { data } = useQuery ( GET_NEW_COMMENTS , SSR
30
31
? { }
@@ -36,15 +37,22 @@ export default function useLiveComments (rootId, after, sort) {
36
37
useEffect ( ( ) => {
37
38
if ( ! data ?. newComments ) return
38
39
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
41
49
setLatest ( prevLatest => getLatestCommentCreatedAt ( data . newComments . comments , prevLatest ) )
42
50
} , [ data , client , rootId , sort ] )
43
51
}
44
52
45
53
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
+
48
56
for ( const newComment of newComments ) {
49
57
console . log ( 'newComment' , newComment )
50
58
const { parentId } = newComment
@@ -58,14 +66,28 @@ function cacheNewComments (client, rootId, newComments, sort) {
58
66
return { item : mergeNewComment ( data ?. item , newComment ) }
59
67
} )
60
68
} 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'
66
74
} )
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
+ }
67
87
}
68
88
}
89
+
90
+ return { queuedComments }
69
91
}
70
92
71
93
// merge new comment into item's newComments
0 commit comments