Ordinary-claude-skills react-native-expo
git clone https://github.com/Microck/ordinary-claude-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/Microck/ordinary-claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills_all/react-native-expo" ~/.claude/skills/microck-ordinary-claude-skills-react-native-expo && rm -rf "$T"
skills_all/react-native-expo/SKILL.mdReact 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
- use DevTools Consoleconsole.log() - 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
display: contentsMakes 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
boxSizingControl 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
mixBlendModeisolationBlend 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
outlineVisual 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)
useActionStateimport { 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)
useOptimisticimport { 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)
useimport { 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
in CLIj - 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
for build errorsreferences/new-architecture-errors.md - Check
for React 19 issuesreferences/react-19-migration.md - 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.