-
-
Notifications
You must be signed in to change notification settings - Fork 132
Live updates to comment threads #2115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…new comment; cleanup: resolvers, logs
…omments are there
…bility change, light cleanup
… comment injection
… use of constants, general cleanup
…he correct Item query
…fix leak on useEffect because of missing sort atomic apollo cache manipulations; manage top sort not being present in item query cache queue nested comments without a parent, retry on the next poll fix commit messages
… queue comments via state
… dropped comments; ui: show amount of new comments refactor: correct function positioning; cleanup: useless logs
…Comments readFragment fallback to received comment
…ss dedupe on ShowNewComments, count nested ncomments from fresh new comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't fault it. Nice work!
I guess all it needs is removing the layout shift.
Oh, and did you get it to handle limited comment threads?
Thanks! Iterative QA made the development slower than it needed to be, but I think that the result is much more sophisticated than what it would've been.
This, and deepest comments support:
Kind of. The fallback mechanism on Not a problem if you're loading the deepest levels yourself, since they're injected with the comment structure we need, but it is a problem if they're already there. I didn't mess with |
fixes: - client-side navigation re-fetched all new comments because 'after' was cached, now the latest new comment time persists in sessionStorage enhancements: - use CommentWithNewMinimal fragment fallback for comments at the deepest level - tweak ReplyOnAnotherPage to show also how many direct new comments are there cleanup: - queue management is not needed anymore, therefore it has been removed
// update latest timestamp to the latest comment created at | ||
// save it to session storage, to persist between client-side navigations | ||
const newLatest = getLatestCommentCreatedAt(data.newComments.comments, latest) | ||
setLatest(newLatest) | ||
if (typeof window !== 'undefined') { | ||
window.sessionStorage.setItem(latestKey, newLatest) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Client-side navigations would make the hook refetch (from cache) from the first timestamp it received.
Other than being a performance waste, it tried to inject new comments on comments that already have them, triggering deduplication every time.
Riding this bug, deduplication doesn't even work on comments at the deepest level as they lack the comments
field, so it would perpetually inject new comments, even if they're there.
Now the latest new comment timestamp persists via sessionStorage
, win win
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option might be to use the logic we already have in lib/new-comments.js
which handles the new comment outlining, and could allow you to use this value to solve outlining issues. I don't know though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is, outlining works somewhat correctly if you visit the post with client-side navigation, but if you visit it by its url, it fails because there isn't commentsViewedAt
in the query params. I think I can work around this and make it work without the local injected
field!
Here I update commentsViewedAt
so that on the next visit, you don't get new comments you may have injected as unread:
const latestCommentCreatedAt = getLatestCommentCreatedAt(freshNewComments, data.createdAt)
const rootId = data.path.split('.')[0]
commentsViewedAfterComment(rootId, latestCommentCreatedAt)
But, wait, I just discovered a bug: I'm calling commentsViewedAfterComment
after injecting a batch of comments, ignoring that the function was made only for single replies, since it updates commentsViewedNum
by 1
stacker.news/lib/new-comments.js
Lines 11 to 15 in 56a185d
export function commentsViewedAfterComment (rootId, createdAt) { | |
window.localStorage.setItem(`${COMMENTS_VIEW_PREFIX}:${rootId}`, new Date(createdAt).getTime()) | |
const existingRootComments = window.localStorage.getItem(`${COMMENTS_NUM_PREFIX}:${rootId}`) || 0 | |
window.localStorage.setItem(`${COMMENTS_NUM_PREFIX}:${rootId}`, existingRootComments + 1) | |
} |
Pushing a patch to also add totalNComments
.
Sadly I can't use commentsViewedAt
for live comments, as it gets updated only when new comments are showed (new comments that have not been shown will be outlined this way on next visit).
oh well, that was actually happening before too, maybe we never reached a point in which if (viewedAt && viewNum) {
return viewedAt < new Date(item.lastCommentAt).getTime() || viewNum < item.ncomments
} edit: just realized that if you visit a post for the first time and comment in dev, the new comment dot appears even if it's yours. Hmm edit2: Ah, it's based off stacker.news/components/item-full.js Lines 164 to 166 in 56a185d
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: CSS Redundancy Causes Maintenance Issues
Duplicate CSS definitions for .newCommentDot
and @keyframes pulse
have been added to components/header.module.css
. These styles are already defined and used in components/comment.module.css
, making the additions to header.module.css
redundant and unused. This duplication can lead to maintenance issues and potential style inconsistencies.
components/header.module.css#L114-L141
Was this report helpful? Give feedback by reacting with 👍 or 👎
…ction logic - top-level and nested comment handling share the same recursion logic - ShowNewComments references the item object for every type of comments — note: item from item-full.js is passed to comments.js - depth now starts at 0 to support top level comments - injection and counting now reach the deepest level, updating also the deepest comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Comment Access Fails Without Null Check
The prepareComments
function attempts to access data.comments.comments
without null-checking data.comments
. For comments at the deepest levels, which may not include a comments
field in their data structure, this results in a runtime error. The access should use optional chaining with a fallback, e.g., data.comments?.comments || []
.
components/show-new-comments.js#L45-L46
stacker.news/components/show-new-comments.js
Lines 45 to 46 in 1d6e69b
...data, | |
comments: { ...data.comments, comments: [...newComments, ...data.comments.comments] }, |
Bug: Depth Logic and Ancestor Counting Bugs
The injectNewComments
function has two issues:
- Incorrect Depth Logic: The
if (depth === 0)
condition withininjectNewComments
incorrectly determines if an item is top-level. Thedepth
parameter passed to thetraverseNewComments
callback represents the current item's depth, not whether the injection itself is for a top-level item. Consequently,itemUpdateQuery
is never called for top-level items, andcommentUpdateFragment
is incorrectly used for all comment injections. - Double-Counting Ancestor Comments: Clicking multiple "show new comments" buttons at different nesting levels causes ancestor comment counts (
ncomments
) to be double-counted. This occurs becauseupdateAncestorsCommentCount
is repeatedly called for the same ancestors when the same new comments are processed multiple times.
components/show-new-comments.js#L77-L93
stacker.news/components/show-new-comments.js
Lines 77 to 93 in 1d6e69b
// recursively processes and displays all new comments and its children | |
// handles comment injection at each level, respecting depth limits | |
function injectNewComments (client, item, currentDepth, sort) { | |
traverseNewComments(client, item, (newComments, item, depth) => { | |
if (newComments.length > 0) { | |
const payload = prepareComments({ client, newComments }) | |
// used to determine if by iterating through the new comments | |
// we are injecting topLevels (depth 0) or not | |
if (depth === 0) { | |
itemUpdateQuery(client, item.id, sort, payload) | |
} else { | |
commentUpdateFragment(client, item.id, payload) | |
} | |
} | |
}, currentDepth) | |
} |
Was this report helpful? Give feedback by reacting with 👍 or 👎
…ccess it on injection
Ah! Sorry about it, that wasn't supposed to happen. We can make space for it in the I'll look into this right now. |
…o avoid vertical layout shifting
Description
Closes #791
It features a
useLiveComments
hook that incrementally fetches comments newer than the lastcommentAt
timestamp, performing cache updates to thenewComments
field of the parentItem
/Comment
.New comments can be showed with a "X new comments" button that will retrieve fresh copies of the
newComments
from the cache and inject them in the parent'scomment
field.Media
Desktop
Screen.Recording.2025-07-15.at.13.23.33.mp4
Mobile
Untitled.mp4
Additional Context
Live comments features:
Known bugs:
Checklist
Are your changes backwards compatible? Please answer below:
Yes
On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:
6, strong QA but it might benefit from human comment testing
For frontend changes: Tested on mobile, light and dark mode? Please answer below:
Yes
Did you introduce any new environment variables? If so, call them out explicitly here:
n/a