perf: Extract DeepLinkHandler from Expensify.tsx into its own component#83196
perf: Extract DeepLinkHandler from Expensify.tsx into its own component#83196rlinoz merged 9 commits intoExpensify:mainfrom
Conversation
Move deep link handling logic (cold boot URL capture, HybridApp getInitialURL, and Linking event listener) out of Expensify.tsx into a dedicated DeepLinkHandler component to reduce complexity and improve separation of concerns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@hoangzinh Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be320b3983
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| </> | ||
| )} | ||
|
|
||
| <DeepLinkHandler onInitialUrl={setInitialUrl} /> |
There was a problem hiding this comment.
Mount DeepLinkHandler before migration gate
Placing <DeepLinkHandler /> in the returned JSX means it is not mounted until after if (!isOnyxMigrated) return null;, but the previous deep-link effect in Expensify ran immediately on first mount even while migrations were still running. This shifts Linking.getInitialURL() and endSpan(CONST.TELEMETRY.SPAN_BOOTSPLASH.DEEP_LINK) later by the migration duration, so the deep-link bootsplash span now measures unrelated migration time and can skew startup telemetry/experiments, while also delaying doneCheckingPublicRoom() and unblocking navigation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
I'll can into this one. @mountiny do you think we should do a QA instead to make sure we can await the migrations safely?
There was a problem hiding this comment.
Yeah I think its better to add some QA even if it should be safe, better safe than sorry
There was a problem hiding this comment.
Deeplinking still needs access to Onyx data, and this is should blocked until we apply any pending migrations.
the deep-link bootsplash span now measures unrelated migration time
I find this invalid, migration was and remains async, the span start in the same place. It's true it might take just a big longer to finish this span now.
|
Anyone with power/idea to fix up this CI prettier job? I cannot replicate this fail locally. |
|
Let's note these 2 additional files were not in a scope for this PR, I just had to fix it for prettier to be happy. |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safari |
|
This is a low risk refactor, so I will go ahead and merge. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 @rlinoz 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! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/rlinoz in version: 9.3.25-0 🚀
|
|
🚀 Deployed to production by https://github.com/puneetlath in version: 9.3.25-13 🚀
|
@mountiny @rlinoz @cristipaval @elirangoshen
Explanation of Change
Averages a ~35% improvement on what React has to do while
Sending a messageand ~15% whenOpening a report. Same renders count, just cheaper because we isolated work fromExpensify.tsxinto a renderless component. I expect this to indirectly improve on other metrics too (and things we don't currently track, like how much CPU is required to apply https/pusher updates).TLDR it should get the whole app to be a bit faster all across the board.
Expensify.tsxpreviously held deep link handling logic inline: capturing the cold-boot URL, callingHybridAppModule.getInitialURL(viaLinking.getInitialURL), and registering aLinkingevent listener for subsequent URL changes. This logic required subscribing toONYXKEYS.COLLECTION.REPORTdirectly inside the rootExpensifycomponent, which caused the entire navigation tree to re-render on every report change.This PR extracts all of that into a new renderless component,
DeepLinkHandler, which owns theCOLLECTION.REPORTOnyx subscription in isolation. The rootExpensifycomponent now renders<DeepLinkHandler onInitialUrl={setInitialUrl} />and receives the resolved initial URL via a callback prop. No behavior changes — purely a structural decomposition that improves separation of concerns and reduces unnecessary re-renders at the root.Results: Open report
open-2.txt
open-3.txt
open-4.txt
open.txt
Results: Send a message
report-sending-message.txt
report-sending-message2.txt
Fixed Issues
$ #74367
$ #77173
$ #77176
PROPOSAL: https://expensify.slack.com/archives/C08CZDJFJ77/p1771857147703589?thread_ts=1768988691.656199&cid=C08CZDJFJ77
Tests
Regular deep link test suites apply, this PR should not change anything in the product. This is purely a performance improvement for React's rendering pipeline that isolates re-renders.
Offline tests
N/A
QA Steps
Same as tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand 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