You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`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.
6
+
7
+
Rather than keep patching, we're replacing `InteractionManager.runAfterInteractions` with purpose-built alternatives that are more precise.
8
+
9
+
## Current state
10
+
11
+
`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.
12
+
13
+
## The problem
14
+
15
+
`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.
16
+
17
+
This makes the migration non-trivial: you have to understand *what each call is actually waiting for* before you can pick the right replacement.
18
+
19
+
## The approach
20
+
21
+
**TransitionTracker** is the backbone. It tracks navigation transitions explicitly, so other APIs can hook into transition lifecycle without relying on a global queue.
22
+
23
+
On top of TransitionTracker, existing APIs gain transition-aware callbacks:
24
+
25
+
- Navigation methods accept `afterTransition` — a callback that runs after the triggered navigation transition completes
26
+
- Navigation methods accept `waitForTransition` — the call waits for all ongoing transitions to finish before navigating
27
+
- Keyboard methods accept `afterTransition` — a callback that runs after the keyboard transition completes
28
+
-`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
29
+
30
+
This makes the code self-descriptive: instead of a generic `runAfterInteractions`, each call site says exactly what it's waiting for and why.
31
+
32
+
> **Note:**`TransitionTracker.runAfterTransitions` is an internal primitive. Application code should use the higher-level APIs (`Navigation`, `useConfirmModal`, etc.) rather than importing TransitionTracker directly.
33
+
34
+
## How
35
+
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).
36
+
37
+
## Primitives comparison
38
+
39
+
For reference, here's how the available timing primitives compare:
40
+
41
+
### `requestAnimationFrame` (rAF)
42
+
43
+
- Fires **before the next paint** (~16ms at 60fps)
44
+
- Guaranteed to run every frame if the thread isn't blocked
45
+
- Use for: UI updates that need to happen on the next frame (scroll, layout measurement, enabling a button after a state flush)
46
+
47
+
### `requestIdleCallback`
48
+
49
+
- Fires when the runtime has **idle time** — no pending frames, no urgent work
50
+
- May be delayed indefinitely if the main thread stays busy
51
+
- Accepts a `timeout` option to force execution after a deadline
52
+
- Use for: Non-urgent background work (Pusher subscriptions, search API calls, contact imports)
53
+
54
+
### `InteractionManager.runAfterInteractions` (legacy — do not use)
55
+
56
+
- React Native-specific. Fires after all **ongoing interactions** (animations, touches) complete
57
+
- Tracks interactions via `createInteractionHandle()` — anything that calls `handle.done()` unblocks the queue
58
+
- In practice, this means "run after the current navigation transition finishes"
59
+
- Problem: it's a global queue with no granularity — you can't say "after _this specific_ transition"
Copy file name to clipboardExpand all lines: contributingGuides/REACT_COMPILER.md
+16-59Lines changed: 16 additions & 59 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,82 +8,39 @@ At Expensify, we are early adopters of this tool and aim to fully leverage its c
8
8
9
9
## React Compiler compliance checker
10
10
11
-
We provide a script, `scripts/react-compiler-compliance-check.ts`, which checks for "Rules of React" compliance locally and enforces these in PRs adding or changing React code through a CI check.
11
+
We provide a script, `scripts/react-compiler-compliance-check.ts`, which checks whether React components and hooks compile with React Compiler. It runs in CI on every PR and can also be used locally for quick feedback.
12
12
13
-
### What it does
13
+
### How it works
14
14
15
-
Runs `react-compiler-healthcheck` in verbose mode, parses output, and summarizes which files compiled and which failed, including file, line, column, and reason. It can:
15
+
The script uses `@babel/core`'s `transformSync` with `babel-plugin-react-compiler` directly (no intermediate tools). For each file, the compiler reports whether components/hooks compiled successfully, failed, or weren't found. This produces a three-state result per file: `COMPILED`, `FAILED`, or `SKIPPED` (no components/hooks).
16
16
17
-
- Check all files or a specific file/glob
18
-
- Check only files changed relative to a base branch
19
-
- Optionally generate a machine-readable report `react-compiler-report.json`
20
-
- Exit with non-zero code when failures are found (useful for CI)
17
+
### CI enforcement (two rules)
21
18
22
-
### Usage
23
-
24
-
> [!NOTE]
25
-
> This script uses `origin` as the base remote by default. If your GH remote is named differently, use the `--remote <name>` flag.
26
-
27
-
#### Check entire codebase or a specific file/glob
28
-
29
-
```bash
30
-
npm run react-compiler-compliance-check check # Check all files
31
-
npm run react-compiler-compliance-check check src/path/Component.tsx # Check specific file
32
-
npm run react-compiler-compliance-check check "src/**/*.tsx"# Check glob pattern
33
-
```
34
-
35
-
#### Check only changed files (against main)
36
-
37
-
```bash
38
-
npm run react-compiler-compliance-check check-changed
39
-
```
40
-
41
-
#### Generate a detailed report (saved as `./react-compiler-report.json`)
42
-
43
-
You can use the `--report` flag with both of the above commands:
19
+
The CI check (`check-changed`) enforces two rules on changed `.ts` and `.tsx` files:
44
20
45
-
```bash
46
-
npm run react-compiler-compliance-check check --report
47
-
npm run react-compiler-compliance-check check-changed --report
48
-
```
49
-
50
-
#### Additional flags
51
-
52
-
**Filter by diff changes (`--filterByDiff`)**
21
+
1.**New files**: If a new file contains components or hooks that fail to compile, the check fails.
22
+
2.**Modified files**: If a file compiled successfully on `main` but fails on the PR branch, the check fails (regression).
53
23
54
-
Only check files that have been modified in the current diff. This is useful when you want to focus on files that have actual changes:
55
-
56
-
```bash
57
-
npm run react-compiler-compliance-check check --filterByDiff
58
-
npm run react-compiler-compliance-check check-changed --filterByDiff
59
-
```
24
+
Files with no React components or hooks are silently skipped.
0 commit comments