LHNOptionsList previously owned the entire empty-inbox UI inline: three hooks (useTheme, useMemoizedLazyExpensifyIcons, useEmptyLHNIllustration), one useMemo for subtitle JSX construction, and a conditional BlockingView render. These ran on every mount of LHNOptionsList, including the 99%+ of renders where data.length > 0 and the empty state is never shown.
This PR:
- Extracts the empty state UI into a new
LHNEmptyState component that only mounts when the inbox is actually empty
- Moves the conditional to
SidebarLinks (parent level), so LHNOptionsList never mounts with empty data
- Removes dead code from
LHNOptionsList: 3 hook calls, emptyLHNSubtitle useMemo (12 deps), conditional BlockingView render, and 7 unused imports. Kept the "Woohoo! All caught up" logging useEffect for observability.
- Removes a duplicate
useOnyx(REPORT_ACTIONS) subscription from OptionRowLHNData (was identical to the existing reportActions prop)
- Removes redundant
useConfirmReadyToOpenApp from SidebarLinks (parent BaseSidebarScreen already calls it)
- Replaces deprecated
absoluteFillObject with absoluteFill
ManualNavigateToInboxTab span benchmark (10 runs each, iOS Simulator, same session):
| Metric |
main |
branch |
| Avg |
675ms |
622ms |
| Min |
615ms |
558ms |
| Max |
761ms |
724ms |
Delta: -53ms (-7.8%). Perf-neutral to marginally better.
Validated against Onyx rules, React Compiler rules, React Native best practices, and Expensify coding standards. UI is identical between main and branch (verified via accessibility tree diff and visual screenshot comparison).
PR: #86964
Issue Owner
Current Issue Owner: @BartekObudzinski
LHNOptionsListpreviously owned the entire empty-inbox UI inline: three hooks (useTheme,useMemoizedLazyExpensifyIcons,useEmptyLHNIllustration), oneuseMemofor subtitle JSX construction, and a conditionalBlockingViewrender. These ran on every mount ofLHNOptionsList, including the 99%+ of renders wheredata.length > 0and the empty state is never shown.This PR:
LHNEmptyStatecomponent that only mounts when the inbox is actually emptySidebarLinks(parent level), soLHNOptionsListnever mounts with empty dataLHNOptionsList: 3 hook calls,emptyLHNSubtitleuseMemo (12 deps), conditionalBlockingViewrender, and 7 unused imports. Kept the "Woohoo! All caught up" logging useEffect for observability.useOnyx(REPORT_ACTIONS)subscription fromOptionRowLHNData(was identical to the existingreportActionsprop)useConfirmReadyToOpenAppfromSidebarLinks(parentBaseSidebarScreenalready calls it)absoluteFillObjectwithabsoluteFillManualNavigateToInboxTab span benchmark (10 runs each, iOS Simulator, same session):
Delta: -53ms (-7.8%). Perf-neutral to marginally better.
Validated against Onyx rules, React Compiler rules, React Native best practices, and Expensify coding standards. UI is identical between main and branch (verified via accessibility tree diff and visual screenshot comparison).
PR: #86964
Issue Owner
Current Issue Owner: @BartekObudzinski