perf(mobile): thread rows no longer re-render the list when another thread streams#21255
Thread list rows re-rendered on every Home or sidebar render, even with nothing in them changed. With another thread streaming, each commit re-rendered every visible row and its menus and swipe actions.
Two things gave the memoized ThreadListV2Row new handler props each time:
useConfirmDeleteThreadcalled no hooks, so the React Compiler skipped it and returned a new delete closure on every render. It is now a plainconfirmThreadDeletionfunction, and the hook builds its handler inline, where the compiler caches it.HomeScreenwrapped callbacks asprops.onX(...)only to drop a returned promise. The compiler caches those closures on the wholepropsobject, which changes on every parent render. They now pass the callbacks straight through. The sidebar's select and pull request handlers also close the open swipe row, so they stay closures, but over destructured callbacks.
I checked this on the device with an identity probe: before, handleRenameThread was new on every Home render; after, only the list data changes.
Renders on the device
Pixel 9 API 36 emulator, dev client, measure-renders.mts, median of 3 runs, same base (layer 8) and device. The provider sets the pace, so the comparison is per commit.
| Scenario | Renders per commit before | After | Commits (before / after) |
|---|---|---|---|
Another thread streams while on Home (--route /) | 433 | 83 | 12 / 15 |
| Another thread streams while on a different thread | 402 | 89 | 8 / 5 |
| The open thread streams | 64 | 41 | 37 / 39 |
| Component, Home scenario | Before | After |
|---|---|---|
View | 2532 | 580 |
Menu | 65 | 10 |
ThreadListV2Row | 64 | 7 |
ThreadSwipeable | 35 | 7 |
On Android I swiped a Home row, used Settle, and opened the row menu.
Claude Opus 5.5 via Claude Code.
🤖 Generated with Claude Code
Checks
Approvability
Verdict: Approved at 0742a8e
Macroscope's review found this PR approvable — This is a focused mobile performance refactor that preserves thread actions and swipe-row behavior while stabilizing callback identities to avoid unnecessary row renders. It introduces no new capability, schema change, product-default change, or static-analysis override.
Notes:
- All code in this push has already been reviewed. Approvability was decided on eligibility alone.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review. 🎉
ℹ️ Recent review info
⚙️ Run configuration
- Configuration used: Path: .coderabbit.config.ts
- Review profile: CHILL
- Plan: Team
- Run ID:
d1e34367-eb21-491d-a81c-48d34c9a6d2c
📥 Commits
Reviewing files that changed from the base of the PR and between 4b2cebf7622054da09372a773537db33174636de and 01223e621cdcd51d64b9112726cf0a8d2dfca83e.
📒 Files selected for processing: 2
apps/mobile/src/features/home/HomeScreen.tsxapps/mobile/src/features/threads/ThreadNavigationSidebar.tsx
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.
📝 Walkthrough
Mobile thread handlers now reference callbacks directly. Active and archived thread hooks call a shared deletion-confirmation function that retains the permission check and confirmation prompt.
Changes: Mobile thread actions
Layer / File(s) Summary Use destructured thread callbacks
apps/mobile/src/features/home/HomeScreen.tsx,apps/mobile/src/features/threads/ThreadNavigationSidebar.tsxHome handlers reference action callbacks directly instead of using wrappers. Sidebar handlers call destructured callbacks and still close the open swipeable row. Call deletion confirmation directly
apps/mobile/src/features/home/useThreadListActions.tsThe confirmation function accepts the action executor and thread. Active and archived thread hooks call it directly, with the existing permission check and confirmation prompt. Priority: ➖ Normal
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Refactor
Suggested reviewers:
t3dotgg
Merge Risk: ⚪ Minimal · up to 01223
The changes preserve the inspected thread-action and deletion behavior, with no material user-facing regression established. The PR appears ready to merge after normal checks.
Pre-merge checks: Passed 3 · Failed 1
Failed Failed checks: 1 warning
Check name Status Explanation Resolution Description check Warning The description explains the problem, implementation, and measured verification results. It does not include the required Scope and approval section, and it does not provide before/after screenshots o… Add a Scope and approval section with the triaged issue or maintainer approval, or explain why this focused fix qualifies for an exemption. Add clear before/after screenshots, plus a short recording if needed to demonstrate the interaction … Passed Passed checks: 3 passed
Check name Status Explanation Linked Issues check Passed Check skipped because no linked issues were found for this pull request. Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request. Title check Passed The title clearly identifies the mobile performance improvement: thread rows no longer re-render when another thread streams.
Full details: Description check
Explanation
The description explains the problem, implementation, and measured verification results. It does not include the required Scope and approval section, and it does not provide before/after screenshots or recording evidence for the UI change.
Resolution
Add a Scope and approval section with the triaged issue or maintainer approval, or explain why this focused fix qualifies for an exemption. Add clear before/after screenshots, plus a short recording if needed to demonstrate the interaction behavior.
- Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
- Commit to this branch
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
Thread transfer impact
⚠️ The latest CI run did not produce a thread transfer result for 0742a8e.
This comment will update automatically after the next completed run.
Added 1 commit
- perf(mobile): thread rows no longer re-render when another thread streams0742a8e