--- name: react-native-expo description: | Build React Native 0.76+ apps with Expo SDK 52-54. Covers mandatory New Architecture (0.82+/SDK 55+), React 19 changes, SDK 54 breaking changes (expo-av, expo-file-system, Reanimated v4), and Swift iOS template. Prevents 16 documented errors. Use when building Expo apps, migrating to New Architecture, upgrading to SDK 54+, or fixing Fabric, TurboModule, propTypes, expo-updates crashes, or Swift AppDelegate errors. user-invocable: true --- # React Native Expo (0.76-0.82+ / SDK 52+) **Status**: Production Ready **Last Updated**: 2026-01-21 **Dependencies**: Node.js 20.19.4+, Expo CLI, Xcode 16.1+ (iOS) **Latest Versions**: react-native@0.81.5, expo@~54.0.31, react@19.2.3 --- ## Quick Start (15 Minutes) ### 1. Create New Expo Project (RN 0.76+) ```bash # Create new Expo app with React Native 0.76+ npx create-expo-app@latest my-app cd my-app # Install latest dependencies npx expo install react-native@latest expo@latest ``` **Why this matters:** - Expo SDK 52+ uses React Native 0.76+ with New Architecture enabled by default - New Architecture is **mandatory** in React Native 0.82+ (cannot be disabled) - Hermes is the only supported JavaScript engine (JSC removed from Expo Go) ### 2. Verify New Architecture is Enabled ```bash # Check if New Architecture is enabled (should be true by default) npx expo config --type introspect | grep newArchEnabled ``` **CRITICAL:** - React Native 0.82+ **requires** New Architecture - legacy architecture completely removed - If migrating from 0.75 or earlier, upgrade to 0.76-0.81 first to use the interop layer - Never try to disable New Architecture in 0.82+ (build will fail) ### 3. Start Development Server ```bash # Start Expo dev server npx expo start # Press 'i' for iOS simulator # Press 'a' for Android emulator # Press 'j' to open React Native DevTools (NOT Chrome debugger!) ``` **CRITICAL:** - Old Chrome debugger removed in 0.79 - use React Native DevTools instead - Metro terminal no longer streams `console.log()` - use DevTools Console - Keyboard shortcuts 'a'/'i' work in CLI, not Metro terminal --- ## Critical Breaking Changes (Dec 2024+) ### 🔴 New Architecture Mandatory (0.82+) **SDK Timeline:** - **Expo SDK 54** (React Native 0.81): Last release supporting Legacy Architecture - **Expo SDK 55** (React Native 0.83): New Architecture mandatory, Legacy completely removed **What Changed:** - **0.76-0.81 / SDK 52-54**: New Architecture default, legacy frozen (no new features) - **0.82+ / SDK 55+**: Legacy Architecture **completely removed** from codebase **Impact:** ```bash # This will FAIL in 0.82+ / SDK 55+: # gradle.properties (Android) newArchEnabled=false # ❌ Ignored, build fails # iOS RCT_NEW_ARCH_ENABLED=0 # ❌ Ignored, build fails ``` **Migration Path:** 1. Upgrade to 0.76-0.81 / SDK 54 first (if on 0.75 or earlier) 2. Test with New Architecture enabled 3. Fix incompatible dependencies (Redux, i18n, CodePush, Reanimated v3 → v4) 4. Then upgrade to 0.82+ / SDK 55+ **Source:** [Expo SDK 54 Changelog](https://expo.dev/changelog/sdk-54) ### 🔴 propTypes Removed (React 19 / RN 0.78+) **What Changed:** React 19 removed `propTypes` completely. No runtime validation, no warnings - silently ignored. **Before (Old Code):** ```typescript import PropTypes from 'prop-types'; function MyComponent({ name, age }) { return {name} is {age}; } MyComponent.propTypes = { // ❌ Silently ignored in React 19 name: PropTypes.string.isRequired, age: PropTypes.number }; ``` **After (Use TypeScript):** ```typescript type MyComponentProps = { name: string; age?: number; }; function MyComponent({ name, age }: MyComponentProps) { return {name} is {age}; } ``` **Migration:** ```bash # Use React 19 codemod to remove propTypes npx @codemod/react-19 upgrade ``` ### 🔴 forwardRef Deprecated (React 19) **What Changed:** `forwardRef` no longer needed - pass `ref` as a regular prop. **Before (Old Code):** ```typescript import { forwardRef } from 'react'; const MyInput = forwardRef((props, ref) => { // ❌ Deprecated return ; }); ``` **After (React 19):** ```typescript function MyInput({ ref, ...props }) { // ✅ ref is a regular prop return ; } ``` ### 🔴 Swift iOS Template Default (0.77+) **What Changed:** New projects use Swift `AppDelegate.swift` instead of Objective-C `AppDelegate.mm`. **Old Structure:** ``` ios/MyApp/ ├── main.m # ❌ Removed ├── AppDelegate.h # ❌ Removed └── AppDelegate.mm # ❌ Removed ``` **New Structure:** ```swift // ios/MyApp/AppDelegate.swift ✅ import UIKit import React @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, ...) -> Bool { // App initialization return true } } ``` **Migration (0.76 → 0.77):** When upgrading existing projects, you **MUST** add this line: ```swift // Add to AppDelegate.swift during migration import React import ReactCoreModules RCTAppDependencyProvider.sharedInstance() // ⚠️ CRITICAL: Must add this! ``` **Source:** [React Native 0.77 Release Notes](https://reactnative.dev/blog/2025/01/14/release-0.77) ### 🔴 Metro Log Forwarding Removed (0.77+) **What Changed:** Metro terminal no longer streams `console.log()` output. **Before (0.76):** ```bash # console.log() appeared in Metro terminal $ npx expo start > LOG Hello from app! # ✅ Appeared here ``` **After (0.77+):** ```bash # console.log() does NOT appear in Metro terminal $ npx expo start # (no logs shown) # ❌ Removed # Workaround (temporary, will be removed): $ npx expo start --client-logs # Shows logs, deprecated ``` **Solution:** Use React Native DevTools Console instead (press 'j' in CLI). **Source:** [React Native 0.77 Release Notes](https://reactnative.dev/blog/2025/01/14/release-0.77) ### 🔴 Chrome Debugger Removed (0.79+) **What Changed:** Old Chrome debugger (`chrome://inspect`) removed. Use React Native DevTools instead. **Old Method (Removed):** ```bash # ❌ This no longer works: # Open Dev Menu → "Debug" → Chrome DevTools opens ``` **New Method (0.76+):** ```bash # Press 'j' in CLI or Dev Menu → "Open React Native DevTools" # ✅ Uses Chrome DevTools Protocol (CDP) # ✅ Reliable breakpoints, watch values, stack inspection # ✅ JS Console (replaces Metro logs) ``` **Limitations:** - Third-party extensions not yet supported (Redux DevTools, etc.) - Network inspector coming in 0.83 (late 2025) **Source:** [React Native 0.79 Release Notes](https://reactnative.dev/blog/2025/04/release-0.79) ### 🔴 JSC Engine Moved to Community (0.79+) **What Changed:** JavaScriptCore (JSC) first-party support removed from React Native 0.81+ core. Moved to community package. **Before (0.78):** - Both Hermes and JSC bundled in React Native - JSC available in Expo Go **After (0.79+ / React Native 0.81+ / SDK 54):** ```bash # JSC removed from React Native core # If you still need JSC (rare): npm install @react-native-community/javascriptcore ``` **Expo Go:** - SDK 52+: JSC completely removed from Expo Go - Hermes only supported **Note:** JSC will eventually be removed entirely from React Native. **Source:** [Expo SDK 54 Changelog](https://expo.dev/changelog/sdk-54) ### 🔴 Deep Imports Deprecated (0.80+) **What Changed:** Importing from internal paths will break. **Before (Old Code):** ```typescript // ❌ Deep imports deprecated import Button from 'react-native/Libraries/Components/Button'; import Platform from 'react-native/Libraries/Utilities/Platform'; ``` **After:** ```typescript // ✅ Import only from 'react-native' import { Button, Platform } from 'react-native'; ``` **Source:** [React Native 0.80 Release Notes](https://reactnative.dev/blog/2025/06/release-0.80) ### 🔴 Android Edge-to-Edge Mandatory (SDK 54+) **What Changed:** Edge-to-edge display is **enabled in all Android apps by default in SDK 54 and cannot be disabled**. **Impact:** ```json // app.json or app.config.js { "expo": { "android": { // This setting is now IGNORED - edge-to-edge always enabled "edgeToEdgeEnabled": false // ❌ No effect in SDK 54+ } } } ``` **UI Impact:** Content now extends behind system status bar and navigation bar. You must account for insets manually using `react-native-safe-area-context`. **Solution:** ```typescript import { SafeAreaView } from 'react-native-safe-area-context'; function App() { return ( {/* Content respects system bars */} ); } ``` **Source:** [Expo SDK 54 Changelog](https://expo.dev/changelog/sdk-54) --- ## New Features (Post-Dec 2024) ### CSS Properties (0.77+ New Architecture Only) React Native now supports many CSS properties previously only available on web: #### 1. `display: contents` Makes an element "invisible" but keeps its children in the layout: ```typescript {/* This View disappears, but Text still renders */} I'm still here! ``` **Use case:** Wrapper components that shouldn't affect layout. #### 2. `boxSizing` Control how width/height are calculated: ```typescript // Default: padding/border inside box // Content-box: padding/border outside ``` #### 3. `mixBlendMode` + `isolation` Blend layers like Photoshop: ```typescript // Prevent unwanted blending: {/* Blending contained within this view */} ``` **Available modes:** `multiply`, `screen`, `overlay`, `darken`, `lighten`, `color-dodge`, `color-burn`, `hard-light`, `soft-light`, `difference`, `exclusion`, `hue`, `saturation`, `color`, `luminosity` #### 4. `outline` Properties Visual outline that doesn't affect layout (unlike `border`): ```typescript ``` **Key difference:** Outline doesn't change element size or trigger layout recalculations. **Source:** [React Native 0.77 Release Notes](https://reactnative.dev/blog/2025/01/14/release-0.77) ### Android XML Drawables (0.78+) Use native Android vector drawables (XML) as Image sources: ```typescript // Load XML drawable at build time import MyIcon from './assets/my_icon.xml'; // Or with require: ``` **Benefits:** - Scalable vector graphics (resolution-independent) - Smaller APK size vs PNG - Off-thread decoding (better performance) **Constraints:** - Build-time resources only (no network loading) - Android only (iOS still uses SF Symbols or PNG) **Source:** [React Native 0.78 Release Notes](https://reactnative.dev/blog/2025/02/release-0.78) ### React 19 New Hooks #### 1. `useActionState` (replaces form patterns) ```typescript import { useActionState } from 'react'; function MyForm() { const [state, submitAction, isPending] = useActionState( async (prevState, formData) => { // Async form submission const result = await api.submit(formData); return result; }, { message: '' } // Initial state ); return (
{state.message && {state.message}} ); } ``` #### 2. `useOptimistic` (optimistic UI updates) ```typescript import { useOptimistic } from 'react'; function LikeButton({ postId, initialLikes }) { const [optimisticLikes, addOptimisticLike] = useOptimistic( initialLikes, (currentLikes, amount) => currentLikes + amount ); async function handleLike() { addOptimisticLike(1); // Update UI immediately await api.like(postId); // Then update server } return ( ); } ``` #### 3. `use` (read promises/contexts during render) ```typescript import { use } from 'react'; function UserProfile({ userPromise }) { // Read promise directly during render (suspends if pending) const user = use(userPromise); return {user.name}; } ``` **Source:** [React 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) ### React Native DevTools (0.76+) **Access:** - Press `j` in CLI - Or open Dev Menu → "Open React Native DevTools" **Features:** - ✅ Reliable breakpoints (unlike old Chrome debugger) - ✅ Watch values, call stack inspection - ✅ JS Console (replaces Metro logs) - ✅ Chrome DevTools Protocol (CDP) based - ⏳ Network inspector (coming in 0.83) - ❌ Third-party extensions not yet supported **Source:** [React Native DevTools Announcement](https://reactnative.dev/blog/2024/10/release-0.76#react-native-devtools) --- ## Known Issues Prevention This skill prevents **16** documented issues: ### Issue #1: propTypes Silently Ignored **Error:** No error - `propTypes` just doesn't work **Source:** [React 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) **Why It Happens:** React 19 removed runtime propTypes validation **Prevention:** Use TypeScript instead, run `npx @codemod/react-19 upgrade` to remove ### Issue #2: forwardRef Deprecated Warning **Error:** `Warning: forwardRef is deprecated` **Source:** [React 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) **Why It Happens:** React 19 allows `ref` as a regular prop **Prevention:** Remove `forwardRef` wrapper, pass `ref` as prop directly ### Issue #3: New Architecture Cannot Be Disabled (0.82+) **Error:** Build fails with `newArchEnabled=false` **Source:** [React Native 0.82 Release Notes](https://reactnative.dev/blog/2025/10/release-0.82) **Why It Happens:** Legacy architecture completely removed from codebase **Prevention:** Migrate to New Architecture before upgrading to 0.82+ ### Issue #4: "Fabric component descriptor not found" **Error:** `Fabric component descriptor provider not found for component` **Source:** [New Architecture Migration Guide](https://reactnative.dev/docs/new-architecture-intro) **Why It Happens:** Component not compatible with New Architecture (Fabric) **Prevention:** Update library to New Architecture version, or use interop layer (0.76-0.81) ### Issue #5: "TurboModule not registered" **Error:** `TurboModule '[ModuleName]' not found` **Source:** [New Architecture Migration Guide](https://reactnative.dev/docs/new-architecture-intro) **Why It Happens:** Native module needs New Architecture support (TurboModules) **Prevention:** Update library to support TurboModules, or use interop layer (0.76-0.81) ### Issue #6: Swift AppDelegate Missing RCTAppDependencyProvider **Error:** `RCTAppDependencyProvider not found` **Source:** [React Native 0.77 Release Notes](https://reactnative.dev/blog/2025/01/14/release-0.77) **Why It Happens:** When migrating from Objective-C to Swift template **Prevention:** Add `RCTAppDependencyProvider.sharedInstance()` to AppDelegate.swift ### Issue #7: Metro Logs Not Appearing **Error:** `console.log()` doesn't show in terminal **Source:** [React Native 0.77 Release Notes](https://reactnative.dev/blog/2025/01/14/release-0.77) **Why It Happens:** Metro log forwarding removed in 0.77 **Prevention:** Use React Native DevTools Console (press 'j'), or `--client-logs` flag (temporary) ### Issue #8: Chrome Debugger Not Working **Error:** Chrome DevTools doesn't connect **Source:** [React Native 0.79 Release Notes](https://reactnative.dev/blog/2025/04/release-0.79) **Why It Happens:** Old Chrome debugger removed in 0.79 **Prevention:** Use React Native DevTools instead (press 'j') ### Issue #9: Deep Import Errors **Error:** `Module not found: react-native/Libraries/...` **Source:** [React Native 0.80 Release Notes](https://reactnative.dev/blog/2025/06/release-0.80) **Why It Happens:** Internal paths deprecated, strict API enforced **Prevention:** Import only from `'react-native'`, not deep paths ### Issue #10: Redux Store Crashes with New Architecture **Error:** App crashes on Redux store creation **Source:** [Redux Toolkit Migration Guide](https://redux-toolkit.js.org/usage/usage-guide) **Why It Happens:** Old `redux` + `redux-thunk` incompatible with New Architecture **Prevention:** Use Redux Toolkit (`@reduxjs/toolkit`) instead ### Issue #11: i18n-js Unreliable with New Architecture **Error:** Translations not updating, or app crashes **Source:** Community reports (GitHub issues) **Why It Happens:** `i18n-js` not fully compatible with New Architecture **Prevention:** Use `react-i18next` instead ### Issue #12: CodePush Crashes on Android **Error:** Android crashes looking for bundle named `null` **Source:** [CodePush GitHub Issues](https://github.com/microsoft/react-native-code-push/issues) **Why It Happens:** Known incompatibility with New Architecture **Prevention:** Avoid CodePush with New Architecture, or wait for official support ### Issue #13: expo-file-system Legacy API Removed (SDK 55+) **Error:** `Module not found: expo-file-system/legacy` **Source:** [Expo SDK 54 Changelog](https://expo.dev/changelog/sdk-54), [GitHub Issue #39056](https://github.com/expo/expo/issues/39056) **Why It Happens:** Legacy API removed in SDK 55, must migrate to new File/Directory class API **Prevention:** Migrate to new API before upgrading to SDK 55 **Migration Timeline:** - SDK 53 and earlier: Legacy API at `expo-file-system` - SDK 54: Legacy API at `expo-file-system/legacy`, new API at `expo-file-system` (default) - SDK 55: Legacy API removed completely **Old Code (SDK 54 with legacy import):** ```typescript import * as FileSystem from 'expo-file-system/legacy'; await FileSystem.writeAsStringAsync(uri, content); ``` **New Code (SDK 54+ new API):** ```typescript import { File } from 'expo-file-system'; const file = new File(uri); await file.writeString(content); ``` ### Issue #14: expo-av Removed (SDK 55+) **Error:** `Module not found: expo-av` **Source:** [Expo SDK 54 Changelog](https://expo.dev/changelog/sdk-54), [expo-av GitHub](https://github.com/expo/expo-av) **Why It Happens:** Package deprecated in SDK 53, removed in SDK 55 **Prevention:** Migrate to expo-audio and expo-video before SDK 55 **Migration Timeline:** - SDK 52: `expo-video` introduced - SDK 53: `expo-audio` introduced, `expo-av` deprecated - SDK 54: Last release with `expo-av` (no patches) - SDK 55: `expo-av` removed **Migration - Audio:** ```typescript // OLD: expo-av import { Audio } from 'expo-av'; const { sound } = await Audio.Sound.createAsync(require('./audio.mp3')); await sound.playAsync(); // NEW: expo-audio import { useAudioPlayer } from 'expo-audio'; const player = useAudioPlayer(require('./audio.mp3')); player.play(); ``` **Migration - Video:** ```typescript // OLD: expo-av import { Video } from 'expo-av';