Skip to content

[$250] Isolate Expensify's global modals #85634

@mountiny

Description

@mountiny

Proposal here

Background

The root Expensify component serves two roles: it orchestrates application lifecycle (Onyx migration, splash screen, navigation, authentication) and renders six global UI elements that stay mounted for the entire session — GrowlNotification, DelegateNoAccessModalProvider, EmojiPicker, UpdateAppModal, ProactiveAppReviewModalManager, and ScreenShareRequestModal. These modals are stateless relative to the parent; they manage visibility internally or via imperative refs.

Expensify subscribes to five Onyx keys, several of which (LAST_VISITED_PATH, LAST_ROUTE) update during routine navigation. Because eslint-disable directives in the component cause React Compiler to bail out, every re-render produces fresh JSX references for all children — forcing React to walk each child fiber even when nothing changed. Profiling on web and iOS confirms the six modal fibers appear in 97–99% of commits, each costing ~0.5–2ms of reconciliation self-time despite their render functions being ~0.1ms no-ops.

Problem

When Expensify re-renders due to routine navigation-driven Onyx updates, if React reconciles the six co-located global modal subtrees that have no dependency on the changed state, then ~3–8ms of JS thread time per commit is wasted on fiber traversal that produces zero visual changes.

Solution

Move the six global modals out of Expensify and into a dedicated React.memo-wrapped child component. The new component owns only the state it needs (a single rarely-changing prop and one Onyx subscription), so React.memo's shallow comparison bails out on virtually every parent re-render — letting React skip the entire modal subtree instead of walking it. This eliminates ~3–8ms of wasted reconciliation per commit without changing any modal behaviour or visual output.

Measured improvements

  • ~ 20% for web
  • ~7 % for native

Scenario & measurements in the 🧵
Draft PR here

Issue OwnerCurrent Issue Owner: @jmusial
Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~022034235732288543075
  • Upwork Job ID: 2034235732288543075
  • Last Price Increase: 2026-03-18

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.ExternalAdded to denote the issue can be worked on by a contributorReviewingHas a PR in reviewWeeklyKSv2

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions