React Native Roadmap 2026-W23
Week of June 1–7, 2026
Items This Week
| # | Title | Label | Link |
|---|---|---|---|
| 1 | What happened at AppJS 2026? Highlights, new products, and plans for the future | 🟧 EXPO | Read |
| 2 | Talking to JSI in Swift: what changed in SDK 56 | 🟧 EXPO | Read |
| 3 | Native code in Expo SDK 56: inline modules and type generation | 🟧 EXPO | Read |
| 4 | React Status #477: React Compiler in Rust, React 19.2.7, React Spectrum 1.4 | ⚛️ REACT | Read |
| 5 | This Week In React: App.js 2026, Gesture Handler 3.0, SPM for RN, Legend List 3.0 | 🟦 RN | Read |
5-Day Action Plan
🟧 Chunk 1 — Integrate Expo Observe for Production Performance Monitoring
Goal: Get real-world performance metrics (launch time, time-to-interactive, per-screen metrics) flowing into the Expo dashboard so the team can spot regressions after every deploy.
Scope:
- Install
@expo/observein the Expo project - Initialize Observe in the root layout (
app/_layout.tsx) - Enable per-screen metrics for at least 2 high-priority routes using Expo Router's URL-based tracking
- Add one custom event to track a key user action (e.g. checkout started, onboarding completed)
- Verify data appears in the Expo dashboard Observe tab after a release build
Out of scope: Full alerting setup, CI performance thresholds, third-party APM integrations (Sentry, Datadog), or building custom dashboards.
Dependencies: Expo SDK 56, an Expo account on any plan (free tier covers 10,000 MAU for at least 3 months per public beta terms).
Acceptance criteria:
- After a release build, the Expo dashboard Observe tab shows launch time and time-to-interactive data
- Per-screen metrics are visible for the 2 configured routes (warm and cold TTI)
- The custom event appears in the events list in the dashboard
- No observable performance regression on JS bundle size (< 5 KB gzipped addition)
Estimated effort: S
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Integrate Expo Observe (@expo/observe) to capture production performance metrics (launch time, bundle load time, time-to-interactive, per-screen metrics) in an Expo SDK 56 app using Expo Router.
Files to create or modify:
package.json— add@expo/observeapp/_layout.tsx— initialize Observe at the root before rendering childrenapp/(tabs)/index.tsxand one other route — callmarkScreenReady()on first meaningful render- One user action handler — add a
trackEventcall for a key action
Step-by-step instructions:
- Run
npx expo install @expo/observe - In
app/_layout.tsx, importObservefrom@expo/observeand callObserve.initialize({ projectId: process.env.EXPO_PUBLIC_PROJECT_ID })at the top of the root layout component - Wrap the root
<Stack>(or<Tabs>) with<ObserveProvider>from@expo/observe - In each target screen, call
Observe.markScreenReady()when the first meaningful content is visible (typically after data has loaded in auseEffect) - In your key user action handler, call
Observe.trackEvent('checkout_started', { cartSize: items.length }) - Build a release binary (
npx expo run:ios --configuration Releaseor via EAS Build) and run the app on a real device - Open https://expo.dev, navigate to your project → Observe tab, and confirm metrics appear
Acceptance criteria checklist:
-
@expo/observeis listed inpackage.jsondependencies -
Observe.initialize()is called in the root layout -
ObserveProviderwraps the navigation tree - At least 2 screens call
Observe.markScreenReady() - Custom event appears in the Observe dashboard
- No TypeScript errors introduced by the integration
🟧 Chunk 2 — Write an Expo SDK 56 Inline Native Module with Auto-Generated TypeScript Interfaces
Goal: Replace a manual TypeScript interface for a native module with the new SDK 56 inline module system, eliminating boilerplate and keeping types in sync automatically.
Scope:
- Enable
watchedDirectoriesinapp.jsonto point to theapp/directory - Write a Swift inline module (
DeviceInfo.swift) directly in the app folder exposing device model and OS version - Run
npx expo prebuildto synchronize the Xcode project - Use
npx expo-type-information inline-modules-interfaceto generate matching TypeScript types - Import and use the module in a React Native screen
Out of scope: Kotlin/Android side of type generation (Swift/macOS-only in SDK 56), complex native view hierarchies, publishing the inline module as a standalone package.
Dependencies: Expo SDK 56, macOS development machine with Xcode 16+ (Swift type generation requires macOS).
Acceptance criteria:
watchedDirectories: ["app"]is set inapp.jsonapp/DeviceInfo.swiftcontains a valid Expo Module using the DSLnpx expo prebuildcompletes without errors and the Swift file appears in the Xcode project- Running the CLI generates
DeviceInfo.generated.tsandDeviceInfo.tsxnext to the Swift file - A screen calling
requireNativeModule('DeviceInfo').getModel()renders the device model string with no TypeScript errors
Estimated effort: M
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Use Expo SDK 56 inline modules to write a Swift native module (DeviceInfo) directly alongside app files, then auto-generate its TypeScript interface using expo-type-information.
Files to create or modify:
app.json— addwatchedDirectories: ["app"]under theexpokeyapp/DeviceInfo.swift— the inline Expo Module exposing device infoapp/screens/DeviceInfoScreen.tsx— a screen that consumes the native module- (Generated)
app/DeviceInfo.generated.tsandapp/DeviceInfo.tsx
Step-by-step instructions:
- In
app.json, add"watchedDirectories": ["app"]inside theexpoobject - Create
app/DeviceInfo.swiftwith the following content:
import ExpoModulesCore
import UIKit
public class DeviceInfoModule: Module {
public func definition() -> ModuleDefinition {
Name("DeviceInfo")
Function("getModel") { () -> String in
return UIDevice.current.model
}
Function("getOSVersion") { () -> String in
return UIDevice.current.systemVersion
}
}
}
- Run
npx expo prebuild --cleanto update the Xcode project - Run
npx expo-type-information inline-modules-interfaceto generate TypeScript types - In
app/screens/DeviceInfoScreen.tsx, import from the generated file and callgetModel()/getOSVersion()in auseEffect, displaying results in<Text>components - Run
npx expo run:iosand verify the screen shows the correct device model and OS version
Acceptance criteria checklist:
-
watchedDirectories: ["app"]is inapp.json -
app/DeviceInfo.swiftexists and uses the Expo Module DSL -
npx expo prebuildcompletes with no errors -
DeviceInfo.generated.tsis generated with correct TypeScript function signatures - The screen renders the device model and OS version from native code
- No TypeScript errors in the project
🟧 Chunk 3 — Upgrade an Existing Expo Project to SDK 56 and Verify JSI Swift Speedup
Goal: Upgrade from Expo SDK 55 to SDK 56 so all existing Expo native modules automatically benefit from the new Swift/C++ JSI path (1.6–2.3x faster iOS native calls), without any manual module rewrites.
Scope:
- Upgrade Expo SDK to 56 using
npx expo install expo@latest - Fix all package compatibility issues with
npx expo install --fix - Re-run
pod installto pick up the newExpoModulesJSIxcframework - Build a release iOS binary and verify no Objective-C++ bridge errors from Expo modules
- Run a simple benchmark to confirm the performance improvement
Out of scope: Writing new JSI bindings from scratch, migrating non-Expo native modules (e.g., hand-written Turbo Modules), Android Kotlin compiler plugin changes.
Dependencies: Existing Expo SDK 55 project using the Expo Modules API, macOS + Xcode 16+, iOS device or simulator for release testing.
Acceptance criteria:
package.jsonshows"expo": "~56.0.0"(or latest SDK 56 patch)npx expo-doctorreports no critical issues- iOS release build succeeds without Objective-C++ bridge warnings for Expo Modules
- A simple benchmark measuring 1,000 synchronous native calls shows ≥ 1.5x improvement vs SDK 55
- All existing native features (camera, biometrics, notifications, etc.) work correctly after upgrade
Estimated effort: S
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Upgrade an Expo project from SDK 55 to SDK 56 to gain the automatic JSI/Swift performance improvement (1.6–2.3x faster iOS native module calls), then verify the upgrade is complete and measure the speedup.
Files to create or modify:
package.json— bump expo and allexpo-*packages to SDK 56 compatible versionsios/Podfile— re-runpod installto update native dependenciesapp/BenchmarkScreen.tsx— optional screen for measuring native call latency
Step-by-step instructions:
- Run
npx expo install expo@latestto upgrade the Expo SDK - Run
npx expo install --fixto update all Expo packages to SDK 56-compatible versions - Run
npx expo-doctorand resolve any reported critical issues - Delete the
ios/Podsdirectory and runcd ios && pod install(ornpx pod-install) - Build a release build:
npx expo run:ios --configuration Release - (Optional) Create
app/BenchmarkScreen.tsxthat calls a simple native module function in a loop of 1,000 iterations and measures elapsed time withDate.now() - Record the benchmark result and compare with a baseline from SDK 55
- Test all existing native features manually (camera, push notifications, biometrics, etc.)
Acceptance criteria checklist:
-
package.jsonshowsexpo: ~56.0.0 -
npx expo-doctorpasses with no critical errors - iOS release build succeeds on Xcode 16+
- No Objective-C++ bridge errors for Expo Modules in the build log
- Benchmark shows ≥ 1.5x speedup on native calls vs SDK 55
- All existing native features work as expected after the upgrade
🟦 Chunk 4 — Migrate to React Native Gesture Handler 3.0
Goal: Upgrade to Gesture Handler 3.0 (announced at App.js Conf 2026) to benefit from its rewritten architecture with better New Architecture integration and faster gesture recognition on both iOS and Android.
Scope:
- Upgrade
react-native-gesture-handlerto v3.0.x - Verify
GestureHandlerRootViewplacement in the root layout - Migrate any remaining old component-based gesture handlers (
<PanGestureHandler>,<LongPressGestureHandler>, etc.) to the hook-based Gesture API - Test all gesture-heavy screens on both iOS and Android
Out of scope: Writing new gesture interactions from scratch, migrating to Reanimated v4 (separate concern), benchmarking gesture latency, or rewriting shared element transitions.
Dependencies: React Native 0.76+ with New Architecture enabled, existing project using react-native-gesture-handler v2.x.
Acceptance criteria:
package.jsonshows"react-native-gesture-handler": "^3.0.0"- No deprecation warnings in Metro bundler output related to Gesture Handler
- All existing gesture interactions work on iOS and Android
- No TypeScript type errors from the Gesture Handler package
Estimated effort: M
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Upgrade react-native-gesture-handler from v2 to v3.0.0 (released at App.js Conf 2026), adapting all gesture usage to the new API and verifying all gestures work on both platforms.
Files to create or modify:
package.json— bumpreact-native-gesture-handlerto^3.0.0app/_layout.tsx(orApp.tsx) — verifyGestureHandlerRootViewplacement- Any screen using
<PanGestureHandler>,<LongPressGestureHandler>, or<TapGestureHandler>— migrate to the Gesture API
Step-by-step instructions:
- Run
npm install react-native-gesture-handler@^3.0.0 - Check the v3 migration guide at https://docs.swmansion.com/react-native-gesture-handler/docs/migration-guide
- Ensure
GestureHandlerRootView style={{ flex: 1 }}wraps your root navigator - Find all old component-based API usages:
grep -r "PanGestureHandler\|TapGestureHandler\|LongPressGestureHandler" app/ --include="*.tsx"
- Migrate each to the hook-based Gesture API with
<GestureDetector>:<PanGestureHandler>→Gesture.Pan().onUpdate(...)inside<GestureDetector><LongPressGestureHandler>→Gesture.LongPress().onStart(...)inside<GestureDetector><TapGestureHandler>→Gesture.Tap().onEnd(...)inside<GestureDetector>
- Run on iOS simulator:
npx expo run:ios - Run on Android emulator:
npx expo run:android - Manually test every gesture interaction
Acceptance criteria checklist:
-
react-native-gesture-handleris^3.0.0inpackage.json - No old component-based gesture handler imports remain
-
GestureHandlerRootViewstill wraps the root navigator - All gestures work correctly on iOS
- All gestures work correctly on Android
- No TypeScript errors from the Gesture Handler types
- No deprecation warnings in Metro bundler output
⚛️ Chunk 5 — Enable React Compiler (Rust Build) and Remove Redundant Memoization
Goal: Switch on the React Compiler (Rust port, tested at Meta and nearly merged to main as of June 2026) in your React Native project to automatically optimize re-renders, then remove manual useMemo/useCallback that become redundant.
Scope:
- Install the latest
babel-plugin-react-compiler(Rust-powered build) - Configure it in
babel.config.jswithcompilationMode: 'infer' - Fix any Rules of React violations surfaced by the compiler
- Profile 3 screens with React DevTools to confirm reduced re-renders
- Remove at least 5
useMemo/useCallbackcalls now handled by the compiler
Out of scope: Migrating class components, enabling the compiler on a web version, server-side rendering changes, or configuring eslint-plugin-react-compiler.
Dependencies: React 19.x (included in Expo SDK 56), babel-preset-expo, Metro bundler access.
Acceptance criteria:
babel-plugin-react-compileris listed indevDependencieswith the latest version- Metro bundler starts without compilation errors after enabling the plugin
- React DevTools Profiler shows fewer re-renders on at least 3 screens compared to baseline
- No new runtime errors on iOS or Android
- At least 5
useMemo/useCallbackcalls removed from the codebase
Estimated effort: M
Copy/paste this prompt:
Implement the following React Native chunk for your mobile app:
Goal: Enable the React Compiler (Rust build, nearly merged to React main in June 2026) in your Expo React Native project to automatically memoize components and hooks, then remove manual useMemo/useCallback that become redundant.
Files to create or modify:
package.json— addbabel-plugin-react-compilertodevDependenciesbabel.config.js— enable the compiler plugin- Multiple
.tsxcomponent files — remove now-redundantuseMemo/useCallbackcalls
Step-by-step instructions:
- Install the plugin:
npx expo install babel-plugin-react-compiler@latest
- In
babel.config.js, add the plugin:
module.exports = {
presets: ['babel-preset-expo'],
plugins: [
['babel-plugin-react-compiler', {
compilationMode: 'infer',
}]
],
};
- Clear Metro cache and start the bundler:
npx expo start --clear
- Fix any compiler errors (they reveal genuine Rules of React violations). Common issues:
- Mutating state or props directly
- Reading
ref.currentduring render - Calling hooks conditionally
- Open React DevTools Profiler, record an interaction on 3 key screens, and note re-render counts as your baseline
- Search for and remove
useMemo/useCallbackcalls no longer needed:
grep -rn "useMemo\|useCallback" app/ --include="*.tsx"
- Re-profile the same 3 screens and compare render counts against the baseline
- Run the full app on both iOS and Android to verify no new runtime errors
Acceptance criteria checklist:
-
babel-plugin-react-compileris indevDependencies(latest version) -
babel.config.jshas the compiler plugin withcompilationMode: 'infer' - Metro bundler starts without errors after
--clear - No new runtime errors on iOS or Android
- React DevTools Profiler shows reduced re-renders on 3+ screens
- At least 5
useMemo/useCallbackcalls removed from the codebase - All existing features work correctly after the changes