perf(search): cache onFocus handlers per index to stop row re-renders#90441
Conversation
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppios.moviOS: mWeb Safarimsafari.movMacOS: Chrome / Safariweb.mov |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a429b9c2c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
PR ReviewOverall: Good approach — caching per-index handlers to avoid fresh closures on every render is a valid optimization for virtualized lists. A few items to address: 1. Stale cache when
|
|
Codex Review: Didn't find any major issues. Hooray! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@situchan I compared the output of the compiler with and without |
Updated Review (post
|
|
Bug in production: bug.mov |
mountiny
left a comment
There was a problem hiding this comment.
Thanks for this, looks like it could be impactful but also made me wonder if this is a common issue in our lists - if yes, lets make holistical fix
There was a problem hiding this comment.
Are there other lists in the app that would suffer from this same rerendering bug? @TMisiukiewicz @situchan ? if so, can you track them down and create some holistic solution to fix it for these lists and make sure each new list uses optimized solution?
|
🚧 @mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
Regarding Melvin's comment: I think this would be adding a defensive code for a hypothetical future misuse that doesn't currently exist |
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.3.74-7 🚀
Bundle Size Analysis (Sentry): |
|
I reviewed the changes in this PR. This is a purely internal performance optimization that caches No help site documentation changes are required — there are no user-facing behavior changes, new features, UI modifications, or workflow updates in this PR. |
|
🚀 Deployed to production by https://github.com/Beamanator in version: 9.3.74-7 🚀
|
Explanation of Change
Every visible Search row was re-rendering on any list render because its
onFocusprop was a brand-new function each time. The handler captures the row'sindex, so it can't be memoized — a fresh closure is allocated per row, per render.Added
useStableIndexedHandlerthat caches one handler per index in a ref. Same row → sameonFocusreference across renders.Considered alternative solutions:
Fixed Issues
$ #90456
PROPOSAL:
Tests
Offline tests
Same as Tests — focus tracking is local and works offline.
QA Steps
Same as Tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-05-13.at.10.44.47.mov