-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Migration navigation from InteractionManager to TransitionTracker #82587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
roryabraham
merged 51 commits into
Expensify:main
from
software-mansion-labs:migration/interaction-manager
Feb 26, 2026
Merged
Changes from all commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
bf90d6c
Migration navigation from InteractionManager to TransitionTracker
blazejkustra e4d30a7
Migrate dismissModal to TransitionTracker
blazejkustra 8d17a6d
Remove unused DeviceEventEmitter
blazejkustra bae4b6e
Refactor dismissModal and dismissModalWithReport to use async/await f…
blazejkustra 4880c05
Refactor afterTransition callback in WorkspaceInviteMessageComponent …
blazejkustra 0cc1c37
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 3ed418f
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 4dceb99
Fix typecheck
blazejkustra aab188b
Replace InteractionManagerLayout with ScreenLayout
blazejkustra eef1d2b
Add TransitionTracker to ReanimatedModal
blazejkustra a050b00
Refactor keyboard dismiss function to accept options for transition m…
blazejkustra 8a670c9
Fix keyboard behaviour
blazejkustra 28033ae
Remove unnecessary code from keyboard dismiss logic
blazejkustra 4d7fd9b
Cluster usages into first groups
blazejkustra 1a913e7
Add migration guide for Settings Pages in InteractionManager
blazejkustra 2520f67
Add migration guide for Search API operations in InteractionManager
blazejkustra a6a26ed
Update InputFocusManagement documentation to include additional usage…
blazejkustra 556c13f
Add migration guide for Onboarding Tours in InteractionManager
blazejkustra 4c33b65
Add migration guide for Files Validation in InteractionManager
blazejkustra 7018507
Add migration guide for Execution Control in InteractionManager
blazejkustra e7bf207
Add migration guide for Realtime Subscriptions in InteractionManager
blazejkustra 0d81c53
Add migration guide for Navigate After Focus in InteractionManager
blazejkustra eb133d7
Add migration guide for Performance and App Lifecycle in InteractionM…
blazejkustra 2163e79
Add migration guides for various InteractionManager patterns
blazejkustra a7f92b5
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 2029397
Remove outdated InteractionManager migration documentation and add ne…
blazejkustra a3b9c19
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 869728b
Revise InteractionManager migration documentation to clarify the remo…
blazejkustra 967f7bb
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 3ada8cd
Refactor TransitionTracker to remove transition type
blazejkustra 1005d38
Update InteractionManager migration documentation to clarify that `wa…
blazejkustra 79ae3d2
Refactor ScreenLayout to improve type handling for navigation prop an…
blazejkustra e6e30b8
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 58e70f4
Refactor ScreenLayout to use a wrapper function
blazejkustra 2db74e0
Update ModalAfterTransition documentation to reflect migration to use…
blazejkustra aeb0f6a
Add InteractionManager migration documentation, remove other docs
blazejkustra 4acf821
Refine InteractionManager migration documentation
blazejkustra b2186f3
Refactor dismissModal and dismissModalWithReport functions to use pro…
blazejkustra 1c1801c
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 29dc160
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 5b1fd12
Merge branch 'main' of github.com:Expensify/App into migration/intera…
blazejkustra 620b48a
Fix prettier
blazejkustra 69ff82d
Refactor dismissModal function parameters and fix keyboard dismiss logic
blazejkustra 57cc57d
small cleanup + fixes of transitionTracker
collectioneur fdf6bec
add tests for transitionTracker
collectioneur 16d2d69
add waitForUpcomingTransaction argument, to prevent executing callbak…
collectioneur cd9fa98
Merge branch 'main' into migration/interaction-manager
collectioneur 688e0a0
fix after merge
collectioneur daf120c
change promise.then to async await and add JSDoc
collectioneur 5d9f7ac
Merge branch 'main' into migration/interaction-manager
collectioneur a2d5fe5
small cleanup
collectioneur File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| # InteractionManager Migration | ||
|
|
||
| ## Why | ||
|
|
||
| `InteractionManager` is being removed from React Native. We currently maintain a patch to keep it working, but that's a temporary measure and upstream libraries will also drop support over time. | ||
|
|
||
| Rather than keep patching, we're replacing `InteractionManager.runAfterInteractions` with purpose-built alternatives that are more precise. | ||
|
|
||
| ## Current state | ||
|
|
||
| `runAfterInteractions` is used across the codebase for a wide range of reasons: waiting for navigation transitions, deferring work after modals close, managing input focus, delaying scroll operations, and many other cases that are hard to classify. | ||
|
|
||
| ## The problem | ||
|
|
||
| `runAfterInteractions` is a global queue with no granularity. This made it a convenient catch-all, but the intent behind each call is often unclear. Many usages exist simply because it "just worked" as a timing workaround, not because it was the right tool for the job. | ||
|
|
||
| This makes the migration non-trivial: you have to understand *what each call is actually waiting for* before you can pick the right replacement. | ||
|
|
||
| ## The approach | ||
|
|
||
| **TransitionTracker** is the backbone. It tracks navigation transitions explicitly, so other APIs can hook into transition lifecycle without relying on a global queue. | ||
|
|
||
| On top of TransitionTracker, existing APIs gain transition-aware callbacks: | ||
|
|
||
| - Navigation methods accept `afterTransition` — a callback that runs after the triggered navigation transition completes | ||
| - Navigation methods accept `waitForTransition` — the call waits for all ongoing transitions to finish before navigating | ||
| - Keyboard methods accept `afterTransition` — a callback that runs after the keyboard transition completes | ||
| - `useConfirmModal` hook's `showConfirmModal` returns a Promise that resolves **after the modal close transition completes**, so any work awaited after it naturally runs post-transition — no explicit `afterTransition` callback needed | ||
|
|
||
| This makes the code self-descriptive: instead of a generic `runAfterInteractions`, each call site says exactly what it's waiting for and why. | ||
|
|
||
| > **Note:** `TransitionTracker.runAfterTransitions` is an internal primitive. Application code should use the higher-level APIs (`Navigation`, `useConfirmModal`, etc.) rather than importing TransitionTracker directly. | ||
|
|
||
| ## How | ||
| The migration is split into 9 issues. Current status of the migration can be found in the parent Github issue [here](https://github.com/Expensify/App/issues/71913). | ||
|
|
||
| ## Primitives comparison | ||
|
|
||
| For reference, here's how the available timing primitives compare: | ||
|
|
||
| ### `requestAnimationFrame` (rAF) | ||
|
|
||
| - Fires **before the next paint** (~16ms at 60fps) | ||
| - Guaranteed to run every frame if the thread isn't blocked | ||
| - Use for: UI updates that need to happen on the next frame (scroll, layout measurement, enabling a button after a state flush) | ||
|
|
||
| ### `requestIdleCallback` | ||
|
|
||
| - Fires when the runtime has **idle time** — no pending frames, no urgent work | ||
| - May be delayed indefinitely if the main thread stays busy | ||
| - Accepts a `timeout` option to force execution after a deadline | ||
| - Use for: Non-urgent background work (Pusher subscriptions, search API calls, contact imports) | ||
|
|
||
| ### `InteractionManager.runAfterInteractions` (legacy — do not use) | ||
|
|
||
| - React Native-specific. Fires after all **ongoing interactions** (animations, touches) complete | ||
| - Tracks interactions via `createInteractionHandle()` — anything that calls `handle.done()` unblocks the queue | ||
| - In practice, this means "run after the current navigation transition finishes" | ||
| - Problem: it's a global queue with no granularity — you can't say "after _this specific_ transition" | ||
|
|
||
| ### Summary | ||
|
|
||
| | | Timing | Granularity | Platform | | ||
| | ---------------------- | ------------------------- | ------------------------- | --------------------- | | ||
| | `rAF` | Next frame (~16ms) | None — just "next paint" | Web + RN | | ||
| | `requestIdleCallback` | When idle (unpredictable) | None — "whenever free" | Web + RN (polyfilled) | | ||
| | `runAfterInteractions` | After animations finish | Global — all interactions | RN only | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.