Skip to content

Commit e065f17

Browse files
committed
cleanup: move cache manipulation functions, comments for comments.js
- lib/comments.js explanations for its functions - itemUpdateQuery, commentUpdateFragment, getLatestCommentCreatedAt on comments.js - format too many imports from comments.js todo: - we're not deduping comments for isThread, which forces us at this state, to dedupe twice
1 parent 25e8e12 commit e065f17

File tree

3 files changed

+74
-53
lines changed

3 files changed

+74
-53
lines changed

components/show-new-comments.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { useCallback, useMemo } from 'react'
22
import { useApolloClient } from '@apollo/client'
33
import styles from './comment.module.css'
4-
import { itemUpdateQuery, commentUpdateFragment } from './use-live-comments'
5-
import { prepareComments, dedupeNewComments, collectAllNewComments, showAllNewCommentsRecursively } from '@/lib/comments'
4+
import {
5+
itemUpdateQuery,
6+
commentUpdateFragment,
7+
prepareComments,
8+
dedupeNewComments,
9+
collectAllNewComments,
10+
showAllNewCommentsRecursively
11+
} from '../lib/comments'
612

713
export const ShowNewComments = ({ topLevel, sort, comments, itemId, item, setHasNewComments, newComments = [], depth = 1 }) => {
814
const client = useApolloClient()
@@ -12,6 +18,7 @@ export const ShowNewComments = ({ topLevel, sort, comments, itemId, item, setHas
1218
const allNewComments = useMemo(() => {
1319
if (isThread) {
1420
// TODO: well are we only collecting all new comments just for a fancy UI?
21+
// TODO2: also, we're not deduping new comments here, so we're showing duplicates
1522
return collectAllNewComments(item, depth)
1623
}
1724
return dedupeNewComments(newComments, comments)

components/use-live-comments.js

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useQuery, useApolloClient } from '@apollo/client'
22
import { SSR } from '../lib/constants'
3-
import { GET_NEW_COMMENTS, COMMENT_WITH_NEW_LIMITED, COMMENT_WITH_NEW_RECURSIVE } from '../fragments/comments'
4-
import { ITEM_FULL } from '../fragments/items'
3+
import { GET_NEW_COMMENTS } from '../fragments/comments'
54
import { useEffect, useRef, useState } from 'react'
5+
import { itemUpdateQuery, commentUpdateFragment, getLatestCommentCreatedAt } from '../lib/comments'
66

77
const POLL_INTERVAL = 1000 * 10 // 10 seconds
88

@@ -47,46 +47,6 @@ export default function useLiveComments (rootId, after, sort, setHasNewComments)
4747
}, [])
4848
}
4949

50-
// the item query is used to update the item's newComments field
51-
export function itemUpdateQuery (client, id, sort, fn) {
52-
client.cache.updateQuery({
53-
query: ITEM_FULL,
54-
// updateQuery needs the correct variables to update the correct item
55-
// the Item query might have the router.query.sort in the variables, so we need to pass it in if it exists
56-
variables: sort ? { id, sort } : { id }
57-
}, (data) => {
58-
if (!data) return data
59-
return { item: fn(data.item) }
60-
})
61-
}
62-
63-
// update the newComments field of a nested comment fragment
64-
export function commentUpdateFragment (client, id, fn) {
65-
let result = client.cache.updateFragment({
66-
id: `Item:${id}`,
67-
fragment: COMMENT_WITH_NEW_RECURSIVE,
68-
fragmentName: 'CommentWithNewRecursive'
69-
}, (data) => {
70-
if (!data) return data
71-
return fn(data)
72-
})
73-
74-
// sometimes comments can reach their depth limit, and lack adherence to the CommentsRecursive fragment
75-
// for this reason, we update the fragment with a limited version that only includes the CommentFields fragment
76-
if (!result) {
77-
result = client.cache.updateFragment({
78-
id: `Item:${id}`,
79-
fragment: COMMENT_WITH_NEW_LIMITED,
80-
fragmentName: 'CommentWithNewLimited'
81-
}, (data) => {
82-
if (!data) return data
83-
return fn(data)
84-
})
85-
}
86-
87-
return result
88-
}
89-
9050
function cacheNewComments (client, rootId, newComments, sort) {
9151
const queuedComments = []
9252

@@ -126,10 +86,3 @@ function mergeNewComment (item, newComment) {
12686

12787
return { ...item, newComments: [...existingNewComments, newComment.id] }
12888
}
129-
130-
export function getLatestCommentCreatedAt (comments, latest) {
131-
return comments.reduce(
132-
(max, { createdAt }) => (createdAt > max ? createdAt : max),
133-
latest
134-
)
135-
}

lib/comments.js

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { COMMENT_DEPTH_LIMIT } from './constants'
2-
import { commentUpdateFragment, getLatestCommentCreatedAt } from '../components/use-live-comments'
32
import { commentsViewedAfterComment } from './new-comments'
4-
import { COMMENT_WITH_NEW_RECURSIVE } from '../fragments/comments'
3+
import { COMMENT_WITH_NEW_RECURSIVE, COMMENT_WITH_NEW_LIMITED } from '../fragments/comments'
4+
import { ITEM_FULL } from '../fragments/items'
55

6+
// updates the ncomments field of all ancestors of an item/comment in the cache
67
export function updateAncestorsCommentCount (cache, ancestors, increment) {
78
// update all ancestors
89
ancestors.forEach(id => {
@@ -19,11 +20,58 @@ export function updateAncestorsCommentCount (cache, ancestors, increment) {
1920
}
2021

2122
// live comments - cache manipulations
23+
// updates the item query in the cache
24+
// this is used by live comments to update a top level item's newComments field
25+
export function itemUpdateQuery (client, id, sort, fn) {
26+
client.cache.updateQuery({
27+
query: ITEM_FULL,
28+
// updateQuery needs the correct variables to update the correct item
29+
// the Item query might have the router.query.sort in the variables, so we need to pass it in if it exists
30+
variables: sort ? { id, sort } : { id }
31+
}, (data) => {
32+
if (!data) return data
33+
return { item: fn(data.item) }
34+
})
35+
}
36+
37+
// updates a comment fragment in the cache, with a fallback for comments lacking CommentsRecursive
38+
export function commentUpdateFragment (client, id, fn) {
39+
let result = client.cache.updateFragment({
40+
id: `Item:${id}`,
41+
fragment: COMMENT_WITH_NEW_RECURSIVE,
42+
fragmentName: 'CommentWithNewRecursive'
43+
}, (data) => {
44+
if (!data) return data
45+
return fn(data)
46+
})
47+
48+
// sometimes comments can reach their depth limit, and lack adherence to the CommentsRecursive fragment
49+
// for this reason, we update the fragment with a limited version that only includes the CommentFields fragment
50+
if (!result) {
51+
result = client.cache.updateFragment({
52+
id: `Item:${id}`,
53+
fragment: COMMENT_WITH_NEW_LIMITED,
54+
fragmentName: 'CommentWithNewLimited'
55+
}, (data) => {
56+
if (!data) return data
57+
return fn(data)
58+
})
59+
}
60+
61+
return result
62+
}
63+
64+
// filters out new comments, by id, that already exist in the item's comments
65+
// preventing duplicate comments from being injected
2266
export function dedupeNewComments (newComments, comments) {
67+
console.log('dedupeNewComments', newComments, comments)
2368
const existingIds = new Set(comments.map(c => c.id))
2469
return newComments.filter(id => !existingIds.has(id))
2570
}
2671

72+
// recursively collects all new comments from an item and its children
73+
// by respecting the depth limit, we avoid collecting new comments to inject in places
74+
// that are too deep in the tree
2775
export function collectAllNewComments (item, currentDepth = 1) {
2876
const allNewComments = [...(item.newComments || [])]
2977
if (item.comments?.comments && currentDepth < (COMMENT_DEPTH_LIMIT - 1)) {
@@ -34,6 +82,8 @@ export function collectAllNewComments (item, currentDepth = 1) {
3482
return allNewComments
3583
}
3684

85+
// prepares and creates a new comments fragment for injection into the cache
86+
// returns a function that can be used to update an item's comments field
3787
export function prepareComments (client, newComments) {
3888
return (data) => {
3989
// newComments is an array of comment ids that allows us
@@ -69,6 +119,7 @@ export function prepareComments (client, newComments) {
69119
const rootId = data.path.split('.')[0]
70120
commentsViewedAfterComment(rootId, latestCommentCreatedAt)
71121

122+
// return the updated item with the new comments injected
72123
return {
73124
...data,
74125
comments: { ...data.comments, comments: [...freshNewComments, ...data.comments.comments] },
@@ -78,6 +129,8 @@ export function prepareComments (client, newComments) {
78129
}
79130
}
80131

132+
// recursively processes and displays all new comments for a thread
133+
// handles comment injection at each level, respecting depth limits
81134
export function showAllNewCommentsRecursively (client, item, currentDepth = 1) {
82135
// handle new comments at this item level
83136
if (item.newComments && item.newComments.length > 0) {
@@ -96,3 +149,11 @@ export function showAllNewCommentsRecursively (client, item, currentDepth = 1) {
96149
}
97150
}
98151
}
152+
153+
// finds the most recent createdAt timestamp from an array of comments
154+
export function getLatestCommentCreatedAt (comments, latest) {
155+
return comments.reduce(
156+
(max, { createdAt }) => (createdAt > max ? createdAt : max),
157+
latest
158+
)
159+
}

0 commit comments

Comments
 (0)