Challenge: Refactoring a Slow Comment Viewer App
Debug and refactor a slow three-component comment viewer by stabilizing identities, fixing memo and selector behavior, and removing heavy render-phase work to make the UI responsive under React 19.
We'll cover the following...
Problem statement
You’ve been tasked with debugging a small React feature called CommentViewer, a compact UI that displays a list of user comments alongside a live analytics summary. The codebase is small, consisting of just three components: App, CommentList, and StatsPanel. Yet, users report noticeable lag when typing, filtering comments, or when new data arrives.
Upon inspecting the profiler, you notice several performance issues:
CommentListre-renders excessively, even though it is wrapped inReact.memo.StatsPanelperforms heavy computations on every keystroke.Appgenerates unstable derived props, forcing unnecessary work throughout the component tree.
Your goal is to refactor this app so that it behaves like a well-architected React 19 component tree: stable identities, meaningful memo boundaries, correct selector usage, and smooth, responsive interactions.
Technical requirements: Implement the following tasks step by step:
Task 1: Fix App.js (identity stability)
Refactor
App.jsso that:filteris stable across renders.filteredCommentsis stable when the text hasn’t changed.Transition usage is prepared for deferring heavy work (later in
StatsPanel).
You can use
useMemoas needed.
Task 2: Fix CommentList.js (Effective memo boundary)
After your refactor to
App.js,CommentListshould:Re-render only when the visible comments truly change.
Ignore unrelated local UI refresh actions.
Make small additions if needed (e.g., memoizing derived child elements), but the main fix is stabilizing props in the parent.
Task 3: Fix StatsPanel.js (selector stability + heavy work)
Refactor
StatsPanelso that:The selector (
snap) is stable and does not change shape on every render.Heavy analytics computation is moved into
useMemoor wrapped in a transition.StatsPanelonly re-renders when:The comments meaningfully change, or
The multiplier changes in the store.
Task 4: Sanity checks and success criteria
Local UI refresh:
Click “Refresh UI Timestamp.”
After your fix:
Appre-renders (expected)CommentList rendershould not logStatsPanel rendershould not log
If
CommentListorStatsPanelstill logs, props are still unstable.
Store refresh:
Trigger the store-refresh action (e.g., via
store.setMultiplieror an existing store timestamp refresh controlAfter your fix:
StatsPanel rendershould not log unless the multiplier changedCommentList rendershould never log.
If
StatsPanellogs for unrelated store changes, your selector is not yet stable.
Typing behavior:
After the refactor, typing in the search bar should:
Feel noticeably smoother
Trigger far fewer
CommentList renderlogsNot trigger expensive
StatsPanel renderlogs on every keypress
Faulty source code
Below is the broken codebase consisting of App.js, CommentList.js, and StatsPanel.js. All code runs without errors but contains realistic performance traps.