Build React Native 0.76+ apps with Expo SDK 52+. Covers mandatory New Architecture (0.82+), React 19 changes, new CSS properties, and Swift iOS template. Use when building Expo apps, migrating to New Architecture, or fixing Fabric, TurboModule, propTypes, or Swift AppDelegate errors.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
skills listSkill Instructions
name: react-native-expo description: | Build React Native 0.76+ apps with Expo SDK 52. Covers mandatory New Architecture (0.82+), React 19 changes (propTypes/forwardRef removal), new CSS (display: contents, mixBlendMode, outline), Swift iOS template, and DevTools migration.
Use when: building Expo apps, migrating to New Architecture, or troubleshooting "Fabric component not found", "propTypes not a function", "TurboModule not registered", or Swift AppDelegate errors.
React Native Expo (0.76-0.82+ / SDK 52+)
Status: Production Ready Last Updated: 2025-11-22 Dependencies: Node.js 18+, Expo CLI Latest Versions: react-native@0.82, expo@~52.0.0, react@19.1
Quick Start (15 Minutes)
1. Create New Expo Project (RN 0.76+)
# 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
# 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
# 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+)
What Changed:
- 0.76-0.81: New Architecture default, legacy frozen (no new features)
- 0.82+: Legacy Architecture completely removed from codebase
Impact:
# This will FAIL in 0.82+:
# gradle.properties (Android)
newArchEnabled=false # ❌ Ignored, build fails
# iOS
RCT_NEW_ARCH_ENABLED=0 # ❌ Ignored, build fails
Migration Path:
- Upgrade to 0.76-0.81 first (if on 0.75 or earlier)
- Test with New Architecture enabled
- Fix incompatible dependencies (Redux, i18n, CodePush)
- Then upgrade to 0.82+
🔴 propTypes Removed (React 19 / RN 0.78+)
What Changed:
React 19 removed propTypes completely. No runtime validation, no warnings - silently ignored.
Before (Old Code):
import PropTypes from 'prop-types';
function MyComponent({ name, age }) {
return <Text>{name} is {age}</Text>;
}
MyComponent.propTypes = { // ❌ Silently ignored in React 19
name: PropTypes.string.isRequired,
age: PropTypes.number
};
After (Use TypeScript):
type MyComponentProps = {
name: string;
age?: number;
};
function MyComponent({ name, age }: MyComponentProps) {
return <Text>{name} is {age}</Text>;
}
Migration:
# 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):
import { forwardRef } from 'react';
const MyInput = forwardRef((props, ref) => { // ❌ Deprecated
return <TextInput ref={ref} {...props} />;
});
After (React 19):
function MyInput({ ref, ...props }) { // ✅ ref is a regular prop
return <TextInput ref={ref} {...props} />;
}
🔴 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:
// 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:
// Add to AppDelegate.swift during migration
import React
import ReactCoreModules
RCTAppDependencyProvider.sharedInstance() // ⚠️ CRITICAL: Must add this!
Source: React Native 0.77 Release Notes
🔴 Metro Log Forwarding Removed (0.77+)
What Changed:
Metro terminal no longer streams console.log() output.
Before (0.76):
# console.log() appeared in Metro terminal
$ npx expo start
> LOG Hello from app! # ✅ Appeared here
After (0.77+):
# 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
🔴 Chrome Debugger Removed (0.79+)
What Changed:
Old Chrome debugger (chrome://inspect) removed. Use React Native DevTools instead.
Old Method (Removed):
# ❌ This no longer works:
# Open Dev Menu → "Debug" → Chrome DevTools opens
New Method (0.76+):
# 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
🔴 JSC Engine Moved to Community (0.79+)
What Changed: JavaScriptCore (JSC) moved out of React Native core, Hermes is default.
Before (0.78):
- Both Hermes and JSC bundled
- JSC available in Expo Go
After (0.79+):
// If you still need JSC (rare):
{
"dependencies": {
"@react-native-community/javascriptcore": "^1.0.0"
}
}
Expo Go:
- JSC completely removed from Expo Go (SDK 52+)
- Hermes only
Note: JSC will eventually be removed entirely from React Native.
🔴 Deep Imports Deprecated (0.80+)
What Changed: Importing from internal paths will break.
Before (Old Code):
// ❌ Deep imports deprecated
import Button from 'react-native/Libraries/Components/Button';
import Platform from 'react-native/Libraries/Utilities/Platform';
After:
// ✅ Import only from 'react-native'
import { Button, Platform } from 'react-native';
Source: React Native 0.80 Release Notes
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:
<View style={{ display: 'contents' }}>
{/* This View disappears, but Text still renders */}
<Text>I'm still here!</Text>
</View>
Use case: Wrapper components that shouldn't affect layout.
2. boxSizing
Control how width/height are calculated:
// Default: padding/border inside box
<View style={{
boxSizing: 'border-box', // Default
width: 100,
padding: 10,
borderWidth: 2
// Total width: 100 (padding/border inside)
}} />
// Content-box: padding/border outside
<View style={{
boxSizing: 'content-box',
width: 100,
padding: 10,
borderWidth: 2
// Total width: 124 (100 + 20 padding + 4 border)
}} />
3. mixBlendMode + isolation
Blend layers like Photoshop:
<View style={{ backgroundColor: 'red' }}>
<View style={{
mixBlendMode: 'multiply', // 16 modes available
backgroundColor: 'blue'
// Result: purple (red × blue)
}} />
</View>
// Prevent unwanted blending:
<View style={{ isolation: 'isolate' }}>
{/* Blending contained within this view */}
</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):
<View style={{
outlineWidth: 2,
outlineStyle: 'solid', // solid | dashed | dotted
outlineColor: 'blue',
outlineOffset: 4, // Space between element and outline
outlineSpread: 2 // Expand outline beyond offset
}} />
Key difference: Outline doesn't change element size or trigger layout recalculations.
Source: React Native 0.77 Release Notes
Android XML Drawables (0.78+)
Use native Android vector drawables (XML) as Image sources:
// Load XML drawable at build time
import MyIcon from './assets/my_icon.xml';
<Image
source={MyIcon}
style={{ width: 40, height: 40 }}
/>
// Or with require:
<Image
source={require('./assets/my_icon.xml')}
style={{ width: 40, height: 40 }}
/>
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
React 19 New Hooks
1. useActionState (replaces form patterns)
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 (
<form action={submitAction}>
<TextInput name="email" />
<Button disabled={isPending}>
{isPending ? 'Submitting...' : 'Submit'}
</Button>
{state.message && <Text>{state.message}</Text>}
</form>
);
}
2. useOptimistic (optimistic UI updates)
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 (
<Button onPress={handleLike}>
❤️ {optimisticLikes}
</Button>
);
}
3. use (read promises/contexts during render)
import { use } from 'react';
function UserProfile({ userPromise }) {
// Read promise directly during render (suspends if pending)
const user = use(userPromise);
return <Text>{user.name}</Text>;
}
Source: React 19 Upgrade Guide
React Native DevTools (0.76+)
Access:
- Press
jin 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
Known Issues Prevention
This skill prevents 12 documented issues:
Issue #1: propTypes Silently Ignored
Error: No error - propTypes just doesn't work
Source: 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
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
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
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
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
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
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 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
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
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
Why It Happens: Known incompatibility with New Architecture
Prevention: Avoid CodePush with New Architecture, or wait for official support
Migration Guide: 0.72-0.75 → 0.82+
Step 1: Upgrade to Interop Layer First (0.76-0.81)
Why: Can't skip directly to 0.82 if using legacy architecture - you'll lose the interop layer.
# Check current version
npx react-native --version
# Upgrade to 0.81 first (last version with interop layer)
npm install react-native@0.81
npx expo install --fix
Step 2: Enable New Architecture (if not already)
# Android (gradle.properties)
newArchEnabled=true
# iOS
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
# Rebuild
npm run ios
npm run android
Step 3: Fix Incompatible Dependencies
Common incompatibilities:
# Replace Redux with Redux Toolkit
npm uninstall redux redux-thunk
npm install @reduxjs/toolkit react-redux
# Replace i18n-js with react-i18next
npm uninstall i18n-js
npm install react-i18next i18next
# Update React Navigation (if old version)
npm install @react-navigation/native@latest
Step 4: Test Thoroughly
# Run on both platforms
npm run ios
npm run android
# Test all features:
# - Navigation
# - State management (Redux)
# - API calls
# - Deep linking
# - Push notifications
Step 5: Migrate to React 19 (if upgrading to 0.78+)
# Run React 19 codemod
npx @codemod/react-19 upgrade
# Manually verify:
# - Remove all propTypes declarations
# - Remove forwardRef wrappers
# - Update to new hooks (useActionState, useOptimistic)
Step 6: Upgrade to 0.82+
# Only after testing with New Architecture enabled!
npm install react-native@0.82
npx expo install --fix
# Rebuild
npm run ios
npm run android
Step 7: Migrate iOS to Swift (if new project)
New projects (0.77+) use Swift by default. For existing projects:
# Follow upgrade helper
# https://react-native-community.github.io/upgrade-helper/
# Select: 0.76 → 0.77
# CRITICAL: Add this line to AppDelegate.swift
RCTAppDependencyProvider.sharedInstance()
Common Patterns
Pattern 1: Conditional Rendering with New Hooks
import { useActionState } from 'react';
function LoginForm() {
const [state, loginAction, isPending] = useActionState(
async (prevState, formData) => {
try {
const user = await api.login(formData);
return { success: true, user };
} catch (error) {
return { success: false, error: error.message };
}
},
{ success: false }
);
return (
<View>
<form action={loginAction}>
<TextInput name="email" placeholder="Email" />
<TextInput name="password" secureTextEntry />
<Button disabled={isPending}>
{isPending ? 'Logging in...' : 'Login'}
</Button>
</form>
{!state.success && state.error && (
<Text style={{ color: 'red' }}>{state.error}</Text>
)}
</View>
);
}
When to use: Form submission with loading/error states
Pattern 2: TypeScript Instead of propTypes
// Define prop types with TypeScript
type ButtonProps = {
title: string;
onPress: () => void;
disabled?: boolean;
variant?: 'primary' | 'secondary';
};
function Button({ title, onPress, disabled = false, variant = 'primary' }: ButtonProps) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
style={[styles.button, styles[variant]]}
>
<Text style={styles.text}>{title}</Text>
</Pressable>
);
}
When to use: Always (propTypes removed in React 19)
Pattern 3: New CSS for Visual Effects
// Glowing button with outline and blend mode
function GlowButton({ title, onPress }) {
return (
<Pressable
onPress={onPress}
style={{
backgroundColor: '#3b82f6',
padding: 16,
borderRadius: 8,
// Outline doesn't affect layout
outlineWidth: 2,
outlineColor: '#60a5fa',
outlineOffset: 4,
// Blend with background
mixBlendMode: 'screen',
isolation: 'isolate'
}}
>
<Text style={{ color: 'white', fontWeight: 'bold' }}>
{title}
</Text>
</Pressable>
);
}
When to use: Visual effects without affecting layout (New Architecture only)
Using Bundled Resources
Scripts (scripts/)
check-rn-version.sh - Detects React Native version and warns about architecture requirements
Example Usage:
./scripts/check-rn-version.sh
# Output: ✅ React Native 0.82 - New Architecture mandatory
# Output: ⚠️ React Native 0.75 - Upgrade to 0.76+ recommended
References (references/)
react-19-migration.md - Detailed React 19 breaking changes and migration steps
new-architecture-errors.md - Common build errors when enabling New Architecture
expo-sdk-52-breaking.md - Expo SDK 52+ specific breaking changes
When Claude should load these: When encountering migration errors, build failures, or detailed React 19 questions
Assets (assets/)
new-arch-decision-tree.md - Decision tree for choosing React Native version
css-features-cheatsheet.md - Complete examples of new CSS properties
Expo SDK 52+ Specifics
Breaking Changes
JSC Removed from Expo Go:
// This no longer works in Expo Go (SDK 52+):
{
"jsEngine": "jsc" // ❌ Ignored, Hermes only
}
Google Maps Removed from Expo Go (SDK 53+):
# Must use custom dev client for Google Maps
npx expo install expo-dev-client
npx expo run:android
Push Notifications Warning: Expo Go shows warnings for push notifications - use custom dev client for production testing.
New Features (SDK 52)
expo/fetch (WinterCG-compliant):
import { fetch } from 'expo/fetch';
// Standards-compliant fetch for Workers/Edge runtimes
const response = await fetch('https://api.example.com/data');
React Navigation v7:
npm install @react-navigation/native@^7.0.0
Official Documentation
- React Native: https://reactnative.dev
- Expo: https://docs.expo.dev
- React 19: https://react.dev/blog/2024/04/25/react-19-upgrade-guide
- New Architecture: https://reactnative.dev/docs/new-architecture-intro
- Upgrade Helper: https://react-native-community.github.io/upgrade-helper/
- Context7 Library ID: /facebook/react-native
Package Versions (Verified 2025-11-22)
{
"dependencies": {
"react": "^19.1.0",
"react-native": "^0.82.0",
"expo": "~52.0.0",
"@react-navigation/native": "^7.0.0",
"@reduxjs/toolkit": "^2.0.0",
"react-i18next": "^15.0.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"typescript": "^5.7.0"
}
}
Troubleshooting
Problem: Build fails with "Fabric component descriptor not found"
Solution: Library not compatible with New Architecture. Check library docs for New Architecture support, or use interop layer (0.76-0.81 only).
Problem: "propTypes is not a function" error
Solution: React 19 removed propTypes. Use TypeScript for type checking instead. Run npx @codemod/react-19 upgrade.
Problem: console.log() not showing in Metro terminal
Solution: Metro log forwarding removed in 0.77. Use React Native DevTools Console (press 'j') or npx expo start --client-logs (temporary workaround).
Problem: Swift AppDelegate errors during iOS build
Solution: Add RCTAppDependencyProvider.sharedInstance() to AppDelegate.swift. See Swift migration section.
Problem: Redux store crashes on startup
Solution: Use Redux Toolkit instead of legacy redux + redux-thunk. Install @reduxjs/toolkit.
Problem: Can't disable New Architecture in 0.82+
Solution: New Architecture is mandatory in 0.82+. If you need legacy, stay on 0.81 or earlier (not recommended).
Complete Setup Checklist
Use this checklist to verify your setup:
- React Native 0.76+ or Expo SDK 52+ installed
- New Architecture enabled (automatic in 0.82+)
- Hermes engine enabled (default)
- React 19 migration complete (no propTypes, no forwardRef)
- TypeScript configured for type checking
- React Native DevTools accessible (press 'j')
- No deep imports (
react-native/Libraries/*) - Redux Toolkit (not legacy redux)
- react-i18next (not i18n-js)
- iOS builds successfully (Swift template if new project)
- Android builds successfully
- Dev server runs without errors
- All navigation/state management working
Questions? Issues?
- Check
references/new-architecture-errors.mdfor build errors - Check
references/react-19-migration.mdfor React 19 issues - Check official docs: https://reactnative.dev/docs/new-architecture-intro
- Ensure New Architecture is enabled (mandatory in 0.82+)
- Verify all dependencies support New Architecture
Knowledge Gap Filled: This skill covers React Native updates from December 2024+ that LLMs won't know about. Without this skill, Claude would suggest deprecated APIs, removed features, and outdated patterns.
More by jezweb
View allSelf-hosted auth for TypeScript/Cloudflare Workers with social auth, 2FA, passkeys, organizations, RBAC, and 15+ plugins. Requires Drizzle ORM or Kysely for D1 (no direct adapter). Self-hosted alternative to Clerk/Auth.js. Use when: self-hosting auth on D1, building OAuth provider, multi-tenant SaaS, or troubleshooting D1 adapter errors, session caching, rate limits.
/review-skill - Skill Audit Command: Comprehensive skill documentation audit with automated checks and manual review phases.
Build rich text editors with Tiptap - headless editor framework with React and Tailwind v4. Covers SSR-safe setup, image uploads, prose styling, and collaborative editing. Use when creating blog editors, comment systems, or Notion-like apps, or troubleshooting SSR hydration errors, typography issues, or image upload problems.
Run LLMs and AI models on Cloudflare's GPU network with Workers AI. Includes Llama 4, Gemma 3, Mistral 3.1, Flux images, BGE embeddings, streaming, and AI Gateway. Handles 2025 breaking changes. Use when: implementing LLM inference, images, RAG, or troubleshooting AI_ERROR, rate limits, max_tokens, BGE pooling.
