Conversation
UnreadIndicatorUpdater and replaceOptimisticReportWithActualReport both register heavy Onyx collection subscriptions (waitForCollectionCallback: true on COLLECTION.REPORT and COLLECTION.REPORT_ACTIONS) at module import time, competing with critical-path startup reads. Deferring them via requestAnimationFrame after the splash hides removes this I/O contention without missing any data, since both modules receive a full collection snapshot on first subscription. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@arosiclair 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] |
Codecov Report✅ Changes either increased or maintained existing code coverage, great j 10000 ob!
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c05c78bc2e
ℹ️ 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".
There was a problem hiding this comment.
Looking good! Could you just run some before/after performance timing so we have some metrics. Thanks
There was a problem hiding this comment.
Only comment is NAB/could be a follow-up. Code changes look good. I think useEffect ended up simpler than using a headless component and React.lazy
src/Expensify.tsx
Outdated
| import PushNotification from './libs/Notification/PushNotification'; | ||
| // Must be imported statically (outside React lifecycle) so push notification handlers | ||
| // are registered before any push arrives, including Android headless/background wake-ups. | ||
| import './libs/Notification/PushNotification/subscribeToPushNotifications'; |
There was a problem hiding this comment.
Suggestion/potential follow-up:
- move this to the
setuplib to clarify its independence from React lifecycles - wrap a dynamic import in
requestIdleCallbackto defer it, see if that helps.
There was a problem hiding this comment.
If Ill use requestIdleCallback it wont be risky for the subscribeToPushNotifications to not trigger on time similar to previous scenario ? as requestIdleCallback defers execution until the browser/JS thread is idle - and maybe notification can get before that ?
There was a problem hiding this comment.
so when moving it to setup I got very nice improvement of 750ms from before the changes which is around 5% faster :) so I pushed it now @roryabraham
Before median value of 5 runs of manual start up span was while its not big change It still better and also better refactor. |
2202b69
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safari |
|
🚧 @Julesssss 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. |
|
🚀 Deployed to staging by https://github.com/Julesssss in version: 9.3.37-0 🚀
|
Explanation of Change
Defers loading of four non-critical modules —
UnreadIndicatorUpdater,replaceOptimisticReportWithActualReport,subscribeToPushNotifications, andregisterPaginationConfig— until after the splash screen hides,instead of importing them statically at module load time. This is done via direct dynamic import() calls inside a
useEffectinSplashScreenStateContext, triggered whensplashScreenStatetransitions toHIDDEN.Both
UnreadIndicatorUpdaterandreplaceOptimisticReportWithActualReportregister heavyOnyx.connectWithoutViewsubscriptions withwaitForCollectionCallback: trueon large collections (```COLLECTION.REPORT,
COLLECTION.REPORT_ACTIONS, COLLECTION.REPORT_DRAFT_COMMENT
). When imported statically, these subscriptions compete for I/O with the critical-path Onyx reads that gate the splash screen (
SESSION,
IS_CHECKING_PUBLIC_ROOM, preferredLocale). Deferring them removes that contention and allows startup reads to complete faster.
This is safe because
UnreadIndicatorUpdaterandreplaceOptimisticReportWithActualReportuse waitForCollectionCallback: true, meaning they receive a full snapshot of all current data when they first subscribe —no events or updates are missed regardless of when they load.
Fixed Issues
$#84624
Tests
Offline tests
QA Steps
QA team, could you also please re-run the deep linking test case after the app has been killed. Thanks!
// TODO: These must be filled out, or the issue title must include "[No QA]."
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