Flattening a comment thread into a single array works until you need to reply to a reply. Then you're faking depth with parent ids, and every edit or delete means rebuilding the whole list. A recursive tree keeps the shape of the conversation and lets you update just the branch that changed.
๐งฉ Overview
Build a threaded comments UI: render a recursive thread, then reply, edit, collapse, and delete nodes while every update returns a new tree instead of mutating the seed.
๐ https://www.reactchallenges.com/challenges/nested-comments
โ Requirements
- Render the full thread from
initialComments, with replies nested inside their parent. - Each comment shows its author and text, and exposes reply, edit, and delete controls.
- Comments with replies get a collapse control with
aria-expandedthat hides or shows only their replies. - Replying opens a form, appends a trimmed reply authored by "You", and closes it. Empty or whitespace-only text is rejected and the form stays open.
- Editing opens a prefilled editor, saves a trimmed update to that comment only, or cancels to restore the original text.
- Deleting removes the comment and its entire subtree, leaving siblings intact.
- Deleting every comment renders an empty state.
- All updates are immutable: neither the seed tree nor any
repliesarray is mutated.
๐ก Notes
The core idea is a recursive tree update. Map the current level, recurse into replies when the target isn't the current node, and rebuild only the nodes on that path:
function updateComment(
comments: Comment[],
id: string,
update: (comment: Comment) => Comment,
): Comment[] {
return comments.map((comment) =>
comment.id === id
? update(comment)
: { ...comment, replies: updateComment(comment.replies, id, update) },
);
}
Reply and edit both reuse it: one callback appends a reply, the other returns { ...comment, text }.
Collapse is UI state, not tree data. Keep the collapsed ids in a Set and let rendering hide the replies, so the branch still exists in the tree.
Delete is the same walk with filter instead of map, which removes the whole subtree in one pass.
๐งช Tests
- renders all seed comments with replies nested under their parent
- shows the author and text of every comment
- collapses a comment's replies and keeps the comment visible
- expands a collapsed comment again
- opens the reply form under the correct comment
- adds a reply with the author You and closes the form
- rejects an empty or whitespace-only reply and keeps the form open
- prefills the editor with the current comment text
- saves an edited comment and closes the editor
- cancels an edit and restores the original text
- deletes a comment and its replies, keeping siblings intact
- shows the empty state when every comment is deleted
- never mutates the imported seed tree
Once you can update a nested comment thread immutably, you can apply the same helper to file explorers, menus, org charts, and nested settings. That's the skill this challenge gives you: thinking in trees instead of flat lists.
Top comments (0)