react-native-expo by jezweb/claude-skills
npx skills add https://github.com/jezweb/claude-skills --skill react-native-expo状态 : 生产就绪 最后更新 : 2026-01-21 依赖项 : Node.js 20.19.4+, Expo CLI, Xcode 16.1+ (iOS) 最新版本 : react-native@0.81.5, expo@~54.0.31, react@19.2.3
# 使用 React Native 0.76+ 创建新的 Expo 应用
npx create-expo-app@latest my-app
cd my-app
# 安装最新依赖项
npx expo install react-native@latest expo@latest
为何重要:
# 检查新架构是否已启用(默认应为 true)
npx expo config --type introspect | grep newArchEnabled
关键:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
# 启动 Expo 开发服务器
npx expo start
# 按 'i' 打开 iOS 模拟器
# 按 'a' 打开 Android 模拟器
# 按 'j' 打开 React Native DevTools(不是 Chrome 调试器!)
关键:
console.log() - 请使用 DevTools 控制台SDK 时间线:
变更内容:
影响:
# 这在 0.82+ / SDK 55+ 中将失败:
# gradle.properties (Android)
newArchEnabled=false # ❌ 被忽略,构建失败
# iOS
RCT_NEW_ARCH_ENABLED=0 # ❌ 被忽略,构建失败
迁移路径:
来源: Expo SDK 54 更新日志
变更内容: React 19 完全移除了 propTypes。没有运行时验证,没有警告 - 静默忽略。
之前(旧代码):
import PropTypes from 'prop-types';
function MyComponent({ name, age }) {
return <Text>{name} is {age}</Text>;
}
MyComponent.propTypes = { // ❌ 在 React 19 中被静默忽略
name: PropTypes.string.isRequired,
age: PropTypes.number
};
之后(使用 TypeScript):
type MyComponentProps = {
name: string;
age?: number;
};
function MyComponent({ name, age }: MyComponentProps) {
return <Text>{name} is {age}</Text>;
}
迁移:
# 使用 React 19 代码修改工具移除 propTypes
npx @codemod/react-19 upgrade
变更内容: 不再需要 forwardRef - 将 ref 作为常规属性传递。
之前(旧代码):
import { forwardRef } from 'react';
const MyInput = forwardRef((props, ref) => { // ❌ 已弃用
return <TextInput ref={ref} {...props} />;
});
之后(React 19):
function MyInput({ ref, ...props }) { // ✅ ref 是常规属性
return <TextInput ref={ref} {...props} />;
}
变更内容: 新项目使用 Swift AppDelegate.swift 而不是 Objective-C AppDelegate.mm。
旧结构:
ios/MyApp/
├── main.m # ❌ 已移除
├── AppDelegate.h # ❌ 已移除
└── AppDelegate.mm # ❌ 已移除
新结构:
// ios/MyApp/AppDelegate.swift ✅
import UIKit
import React
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, ...) -> Bool {
// 应用初始化
return true
}
}
迁移 (0.76 → 0.77): 升级现有项目时,必须添加这行代码:
// 迁移期间添加到 AppDelegate.swift
import React
import ReactCoreModules
RCTAppDependencyProvider.sharedInstance() // ⚠️ 关键:必须添加此行!
变更内容: Metro 终端不再流式传输 console.log() 输出。
之前 (0.76):
# console.log() 出现在 Metro 终端中
$ npx expo start
> LOG Hello from app! # ✅ 出现在这里
之后 (0.77+):
# console.log() 不会出现在 Metro 终端中
$ npx expo start
# (不显示日志) # ❌ 已移除
# 临时解决方案(将被移除):
$ npx expo start --client-logs # 显示日志,已弃用
解决方案: 请改用 React Native DevTools 控制台(在 CLI 中按 'j')。
变更内容: 旧版 Chrome 调试器 (chrome://inspect) 已移除。请改用 React Native DevTools。
旧方法(已移除):
# ❌ 这不再有效:
# 打开开发菜单 → "调试" → Chrome DevTools 打开
新方法 (0.76+):
# 在 CLI 中按 'j' 或开发菜单 → "打开 React Native DevTools"
# ✅ 使用 Chrome DevTools 协议 (CDP)
# ✅ 可靠的断点、监视值、堆栈检查
# ✅ JS 控制台(替代 Metro 日志)
限制:
变更内容: JavaScriptCore (JSC) 的一级支持已从 React Native 0.81+ 核心中移除。移至社区包。
之前 (0.78):
之后 (0.79+ / React Native 0.81+ / SDK 54):
# JSC 已从 React Native 核心中移除
# 如果仍需要 JSC(罕见情况):
npm install @react-native-community/javascriptcore
Expo Go:
注意: JSC 最终将从 React Native 中完全移除。
来源: Expo SDK 54 更新日志
变更内容: 从内部路径导入将会中断。
之前(旧代码):
// ❌ 深层导入已弃用
import Button from 'react-native/Libraries/Components/Button';
import Platform from 'react-native/Libraries/Utilities/Platform';
之后:
// ✅ 仅从 'react-native' 导入
import { Button, Platform } from 'react-native';
变更内容: 边到边显示在 SDK 54 中默认在所有 Android 应用中启用且无法禁用。
影响:
// app.json 或 app.config.js
{
"expo": {
"android": {
// 此设置现在被忽略 - 边到边显示始终启用
"edgeToEdgeEnabled": false // ❌ 在 SDK 54+ 中无效
}
}
}
UI 影响: 内容现在延伸到系统状态栏和导航栏后面。必须使用 react-native-safe-area-context 手动处理安全区域。
解决方案:
import { SafeAreaView } from 'react-native-safe-area-context';
function App() {
return (
<SafeAreaView style={{ flex: 1 }}>
{/* 内容尊重系统栏 */}
</SafeAreaView>
);
}
来源: Expo SDK 54 更新日志
React Native 现在支持许多以前仅在 Web 上可用的 CSS 属性:
display: contents使元素"不可见"但将其子元素保留在布局中:
<View style={{ display: 'contents' }}>
{/* 此 View 消失,但 Text 仍会渲染 */}
<Text>I'm still here!</Text>
</View>
使用场景: 不应影响布局的包装组件。
boxSizing控制宽度/高度的计算方式:
// 默认:内边距/边框在盒子内部
<View style={{
boxSizing: 'border-box', // 默认
width: 100,
padding: 10,
borderWidth: 2
// 总宽度:100(内边距/边框在内部)
}} />
// 内容盒子:内边距/边框在外部
<View style={{
boxSizing: 'content-box',
width: 100,
padding: 10,
borderWidth: 2
// 总宽度:124 (100 + 20 内边距 + 4 边框)
}} />
mixBlendMode + isolation像 Photoshop 一样混合图层:
<View style={{ backgroundColor: 'red' }}>
<View style={{
mixBlendMode: 'multiply', // 16 种可用模式
backgroundColor: 'blue'
// 结果:紫色 (红色 × 蓝色)
}} />
</View>
// 防止不需要的混合:
<View style={{ isolation: 'isolate' }}>
{/* 混合限制在此视图内 */}
</View>
可用模式: multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity
outline 属性不影响布局的视觉轮廓(与 border 不同):
<View style={{
outlineWidth: 2,
outlineStyle: 'solid', // solid | dashed | dotted
outlineColor: 'blue',
outlineOffset: 4, // 元素和轮廓之间的空间
outlineSpread: 2 // 将轮廓扩展到偏移量之外
}} />
关键区别: 轮廓不改变元素大小或触发布局重新计算。
使用原生 Android 矢量可绘制对象 (XML) 作为 Image 源:
// 在构建时加载 XML 可绘制对象
import MyIcon from './assets/my_icon.xml';
<Image
source={MyIcon}
style={{ width: 40, height: 40 }}
/>
// 或使用 require:
<Image
source={require('./assets/my_icon.xml')}
style={{ width: 40, height: 40 }}
/>
优势:
限制:
useActionState (替代表单模式)import { useActionState } from 'react';
function MyForm() {
const [state, submitAction, isPending] = useActionState(
async (prevState, formData) => {
// 异步表单提交
const result = await api.submit(formData);
return result;
},
{ message: '' } // 初始状态
);
return (
<form action={submitAction}>
<TextInput name="email" />
<Button disabled={isPending}>
{isPending ? '提交中...' : '提交'}
</Button>
{state.message && <Text>{state.message}</Text>}
</form>
);
}
useOptimistic (乐观 UI 更新)import { useOptimistic } from 'react';
function LikeButton({ postId, initialLikes }) {
const [optimisticLikes, addOptimisticLike] = useOptimistic(
initialLikes,
(currentLikes, amount) => currentLikes + amount
);
async function handleLike() {
addOptimisticLike(1); // 立即更新 UI
await api.like(postId); // 然后更新服务器
}
return (
<Button onPress={handleLike}>
❤️ {optimisticLikes}
</Button>
);
}
use (在渲染期间读取 Promise/上下文)import { use } from 'react';
function UserProfile({ userPromise }) {
// 在渲染期间直接读取 Promise(如果待处理则暂停)
const user = use(userPromise);
return <Text>{user.name}</Text>;
}
来源: React 19 升级指南
访问方式:
j功能:
此技能可预防 16 个已记录的问题:
错误: 无错误 - propTypes 就是不工作 来源: React 19 升级指南 发生原因: React 19 移除了运行时 propTypes 验证 预防: 改用 TypeScript,运行 npx @codemod/react-19 upgrade 来移除
错误: Warning: forwardRef is deprecated 来源: React 19 升级指南 发生原因: React 19 允许 ref 作为常规属性 预防: 移除 forwardRef 包装器,直接将 ref 作为属性传递
错误: 使用 newArchEnabled=false 时构建失败 来源: React Native 0.82 发布说明 发生原因: 旧架构已完全从代码库中移除 预防: 在升级到 0.82+ 之前迁移到新架构
错误: Fabric component descriptor provider not found for component 来源: 新架构迁移指南 发生原因: 组件与新架构 (Fabric) 不兼容 预防: 将库更新到支持新架构的版本,或使用互操作层 (0.76-0.81)
错误: TurboModule '[ModuleName]' not found 来源: 新架构迁移指南 发生原因: 原生模块需要新架构支持 (TurboModules) 预防: 将库更新到支持 TurboModules 的版本,或使用互操作层 (0.76-0.81)
错误: RCTAppDependencyProvider not found 来源: React Native 0.77 发布说明 发生原因: 从 Objective-C 迁移到 Swift 模板时 预防: 将 RCTAppDependencyProvider.sharedInstance() 添加到 AppDelegate.swift
错误: console.log() 不显示在终端中 来源: React Native 0.77 发布说明 发生原因: Metro 日志转发已在 0.77 中移除 预防: 使用 React Native DevTools 控制台(按 'j'),或使用 --client-logs 标志(临时)
错误: Chrome DevTools 无法连接 来源: React Native 0.79 发布说明 发生原因: 旧版 Chrome 调试器已在 0.79 中移除 预防: 改用 React Native DevTools(按 'j')
错误: Module not found: react-native/Libraries/... 来源: React Native 0.80 发布说明 发生原因: 内部路径已弃用,强制执行严格 API 预防: 仅从 'react-native' 导入,而不是深层路径
错误: 创建 Redux store 时应用崩溃 来源: Redux Toolkit 迁移指南 发生原因: 旧版 redux + redux-thunk 与新架构不兼容 预防: 改用 Redux Toolkit (@reduxjs/toolkit)
错误: 翻译未更新,或应用崩溃 来源: 社区报告 (GitHub issues) 发生原因: i18n-js 不完全兼容新架构 预防: 改用 react-i18next
错误: Android 在查找名为 null 的包时崩溃 来源: CodePush GitHub Issues 发生原因: 已知与新架构不兼容 预防: 避免在新架构中使用 CodePush,或等待官方支持
错误: Module not found: expo-file-system/legacy 来源: Expo SDK 54 更新日志, GitHub Issue #39056 发生原因: 旧版 API 已在 SDK 55 中移除,必须迁移到新的 File/Directory 类 API 预防: 在升级到 SDK 55 之前迁移到新 API
迁移时间线:
expo-file-systemexpo-file-system/legacy,新 API 位于 expo-file-system(默认)旧代码 (SDK 54 使用旧版导入):
import * as FileSystem from 'expo-file-system/legacy';
await FileSystem.writeAsStringAsync(uri, content);
新代码 (SDK 54+ 新 API):
import { File } from 'expo-file-system';
const file = new File(uri);
await file.writeString(content);
错误: Module not found: expo-av 来源: Expo SDK 54 更新日志, expo-av GitHub 发生原因: 包在 SDK 53 中已弃用,在 SDK 55 中移除 预防: 在 SDK 55 之前迁移到 expo-audio 和 expo-video
迁移时间线:
expo-videoexpo-audio,expo-av 弃用expo-av 的版本(无补丁)expo-av 已移除迁移 - 音频:
// 旧版:expo-av
import { Audio } from 'expo-av';
const { sound } = await Audio.Sound.createAsync(require('./audio.mp3'));
await sound.playAsync();
// 新版:expo-audio
import { useAudioPlayer } from 'expo-audio';
const player = useAudioPlayer(require('./audio.mp3'));
player.play();
迁移 - 视频:
// 旧版:expo-av
import { Video } from 'expo-av';
<Video source={require('./video.mp4')} />
// 新版:expo-video
import { VideoView } from 'expo-video';
<VideoView source={require('./video.mp4')} />
错误: 在旧架构上使用 Reanimated v4 时构建失败或崩溃 来源: Expo SDK 54 FYI 发生原因: Reanimated v4 专门需要新架构 预防: 在旧架构上使用 Reanimated v3,或先迁移到新架构
版本矩阵:
| Reanimated 版本 | 架构支持 | Expo SDK |
|---|---|---|
| v3 | 旧架构 + 新架构 | SDK 52-54 |
| v4 | 仅限新架构 | SDK 54+ |
NativeWind 不兼容性:
# NativeWind 尚不支持 Reanimated v4(截至 2026年1月)
# 如果使用 NativeWind,必须停留在 Reanimated v3
npm install react-native-reanimated@^3
迁移到 v4(仅限新架构):
react-native-worklets(v4 必需)babel-preset-expo,请跳过 babel.config.js 更改(自动配置)错误:
hermes::vm::JSObject::putComputed_RJS
hermes::vm::arrayPrototypePush
来源: GitHub Issue #41824, Medium 文章 已验证: 可复现 发生原因: 在 iOS 上使用新架构时,Expo Updates 需要在 Podfile 中显式设置 :hermes_enabled 标志 预防: 将显式 Hermes 标志添加到 ios/Podfile
条件:
expo-updates解决方案:
# ios/Podfile
use_frameworks! :linkage => :static
ENV['HERMES_ENABLED'] = '1' # ⚠️ 关键:使用新架构 + expo-updates 时必须显式设置
注意: 这是一个社区来源的发现,有复现仓库,尚未在 Expo 更新日志中正式记录。
原因: 如果使用旧架构,不能直接跳到 0.82 - 否则会失去互操作层。
# 检查当前版本
npx react-native --version
# 首先升级到 0.81(最后一个带有互操作层的版本)
npm install react-native@0.81
npx expo install --fix
# Android (gradle.properties)
newArchEnabled=true
# iOS
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
# 重新构建
npm run ios
npm run android
常见不兼容项:
# 用 Redux Toolkit 替换 Redux
npm uninstall redux redux-thunk
npm install @reduxjs/toolkit react-redux
# 用 react-i18next 替换 i18n-js
npm uninstall i18n-js
npm install react-i18next i18next
# 更新 React Navigation(如果是旧版本)
npm install @react-navigation/native@latest
# 在两个平台上运行
npm run ios
npm run android
# 测试所有功能:
# - 导航
# - 状态管理 (Redux)
# - API 调用
# - 深度链接
# - 推送通知
# 运行 React 19 代码修改工具
npx @codemod/react-19 upgrade
# 手动验证:
# - 移除所有 propTypes 声明
# - 移除 forwardRef 包装器
# - 更新到新 hooks (useActionState, useOptimistic)
# 仅在启用新架构测试通过后!
npm install react-native@0.82
npx expo install --fix
# 重新构建
npm run ios
npm run android
新项目 (0.77+) 默认使用 Swift。对于现有项目:
# 遵循升级助手
# https://react-native-community.github.io/upgrade-helper/
# 选择:0.76 → 0.77
# 关键:将此行添加到 AppDelegate.swift
RCTAppDependencyProvider.sharedInstance()
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 ? '登录中...' : '登录'}
</Button>
</form>
{!state.success && state.error && (
<Text style={{ color: 'red' }}>{state.error}</Text>
)}
</View>
);
}
使用时机: 带有加载/错误状态的表单提交
// 使用 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>
);
}
使用时机: 始终(propTypes 已在 React 19 中移除)
// 带有轮廓和混合模式的发光按钮
function GlowButton({ title, onPress }) {
return (
<Pressable
onPress={onPress}
style={{
backgroundColor: '#3b82f6',
padding: 16,
borderRadius: 8,
// 轮廓不影响布局
outlineWidth: 2,
outlineColor: '#60a5fa',
outlineOffset: 4,
// 与背景混合
mixBlendMode: 'screen',
isolation: 'isolate'
}}
>
<Text style={{ color: 'white', fontWeight: 'bold' }}>
{title}
</Text>
</Pressable>
);
}
使用时机: 不影响布局的视觉效果(仅限新架构)
check-rn-version.sh - 检测 React Native 版本并警告架构要求
使用示例:
./scripts/check-rn-version.sh
# 输出:✅ React Native 0.82 - 新架构强制启用
# 输出:⚠️ React Native 0.75 - 建议升级到 0.76+
react-19-migration.md - React 19 破坏性变更和迁移步骤的详细说明
new-architecture-errors.md - 启用新架构时的常见构建错误
expo-sdk-52-breaking.md - Expo SDK 52+ 特定的破坏性变更
Claude 何时应加载这些: 当遇到迁移错误、构建失败或详细的 React 19 问题时
new-arch-decision-tree.md - 选择 React Native 版本的决策树
css-features-cheatsheet.md - 新 CSS 属性的完整示例
Expo Go 中已移除 JSC:
// 这在 Expo Go (SDK 52+) 中不再有效:
{
"jsEngine": "jsc" // ❌ 被忽略,仅限 Hermes
}
Google Maps 已从 Expo Go 中移除 (SDK 53+):
# 必须使用自定义开发客户端进行 Google Maps 测试
npx expo install expo-dev-client
npx expo run:android
推送通知警告: Expo Go 显示推送通知警告 - 请使用自定义开发客户端进行生产测试。
expo/fetch (符合 WinterCG 标准):
import { fetch } from 'expo/fetch';
// 符合标准的 fetch,适用于 Workers/Edge 运行时
const response = await fetch('https://api.example.com/data');
React Navigation v7:
npm install @react-navigation/native@^7.0.0
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
# 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:
# Check if New Architecture is enabled (should be true by default)
npx expo config --type introspect | grep newArchEnabled
CRITICAL:
# 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:
console.log() - use DevTools ConsoleSDK Timeline:
What Changed:
Impact:
# 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:
Source: Expo SDK 54 Changelog
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
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} />;
}
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
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
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:
Source: React Native 0.79 Release Notes
What Changed: JavaScriptCore (JSC) first-party support removed from React Native 0.81+ core. Moved to community package.
Before (0.78):
After (0.79+ / React Native 0.81+ / SDK 54):
# JSC removed from React Native core
# If you still need JSC (rare):
npm install @react-native-community/javascriptcore
Expo Go:
Note: JSC will eventually be removed entirely from React Native.
Source: Expo SDK 54 Changelog
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
What Changed: Edge-to-edge display is enabled in all Android apps by default in SDK 54 and cannot be disabled.
Impact:
// 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:
import { SafeAreaView } from 'react-native-safe-area-context';
function App() {
return (
<SafeAreaView style={{ flex: 1 }}>
{/* Content respects system bars */}
</SafeAreaView>
);
}
Source: Expo SDK 54 Changelog
React Native now supports many CSS properties previously only available on web:
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.
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)
}} />
mixBlendMode + isolationBlend 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, , ,
outline PropertiesVisual 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
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:
Constraints:
Source: React Native 0.78 Release Notes
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>
);
}
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>
);
}
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
Access:
j in CLIFeatures:
Source: React Native DevTools Announcement
This skill prevents 16 documented issues:
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
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
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+
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)
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)
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
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)
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')
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
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
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
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
Error: Module not found: expo-file-system/legacy Source: Expo SDK 54 Changelog, GitHub Issue #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:
expo-file-systemexpo-file-system/legacy, new API at expo-file-system (default)Old Code (SDK 54 with legacy import):
import * as FileSystem from 'expo-file-system/legacy';
await FileSystem.writeAsStringAsync(uri, content);
New Code (SDK 54+ new API):
import { File } from 'expo-file-system';
const file = new File(uri);
await file.writeString(content);
Error: Module not found: expo-av Source: Expo SDK 54 Changelog, expo-av GitHub 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:
expo-video introducedexpo-audio introduced, expo-av deprecatedexpo-av (no patches)expo-av removedMigration - Audio:
// 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:
// OLD: expo-av
import { Video } from 'expo-av';
<Video source={require('./video.mp4')} />
// NEW: expo-video
import { VideoView } from 'expo-video';
<VideoView source={require('./video.mp4')} />
Error: Build fails or crashes with Reanimated v4 on Legacy Architecture Source: Expo SDK 54 FYI Why It Happens: Reanimated v4 exclusively requires New Architecture Prevention: Use Reanimated v3 with Legacy Architecture, or migrate to New Architecture first
Version Matrix:
| Reanimated Version | Architecture Support | Expo SDK |
|---|---|---|
| v3 | Legacy + New Architecture | SDK 52-54 |
| v4 | New Architecture ONLY | SDK 54+ |
NativeWind Incompatibility:
# NativeWind does not support Reanimated v4 yet (as of Jan 2026)
# If using NativeWind, must stay on Reanimated v3
npm install react-native-reanimated@^3
Migration to v4 (New Architecture only):
react-native-worklets (required for v4)babel-preset-expo (auto-configured)Error:
hermes::vm::JSObject::putComputed_RJS
hermes::vm::arrayPrototypePush
Source: GitHub Issue #41824, Medium Post Verified: Reproduction available Why It Happens: Expo Updates requires explicit :hermes_enabled flag in Podfile when using New Architecture on iOS Prevention: Add explicit Hermes flag to ios/Podfile
Conditions:
expo-updatesWorkaround:
# ios/Podfile
use_frameworks! :linkage => :static
ENV['HERMES_ENABLED'] = '1' # ⚠️ CRITICAL: Must be explicit with New Arch + expo-updates
Note: This is a community-sourced finding with reproduction repository, not yet officially documented in Expo changelog.
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
# Android (gradle.properties)
newArchEnabled=true
# iOS
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
# Rebuild
npm run ios
npm run android
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
# Run on both platforms
npm run ios
npm run android
# Test all features:
# - Navigation
# - State management (Redux)
# - API calls
# - Deep linking
# - Push notifications
# Run React 19 codemod
npx @codemod/react-19 upgrade
# Manually verify:
# - Remove all propTypes declarations
# - Remove forwardRef wrappers
# - Update to new hooks (useActionState, useOptimistic)
# Only after testing with New Architecture enabled!
npm install react-native@0.82
npx expo install --fix
# Rebuild
npm run ios
npm run android
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()
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
// 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)
// 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)
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
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
new-arch-decision-tree.md - Decision tree for choosing React Native version
css-features-cheatsheet.md - Complete examples of new CSS properties
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.
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
Build Tool Requirements (SDK 54+):
Source: Expo SDK 54 Changelog
{
"dependencies": {
"react": "^19.2.3",
"react-native": "^0.81.5",
"expo": "~54.0.31",
"@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"
}
}
Solution: Library not compatible with New Architecture. Check library docs for New Architecture support, or use interop layer (0.76-0.81 only).
Solution: React 19 removed propTypes. Use TypeScript for type checking instead. Run npx @codemod/react-19 upgrade.
Solution: Metro log forwarding removed in 0.77. Use React Native DevTools Console (press 'j') or npx expo start --client-logs (temporary workaround).
Solution: Add RCTAppDependencyProvider.sharedInstance() to AppDelegate.swift. See Swift migration section.
Solution: Use Redux Toolkit instead of legacy redux + redux-thunk. Install @reduxjs/toolkit.
Solution: New Architecture is mandatory in 0.82+. If you need legacy, stay on 0.81 or earlier (not recommended).
Use this checklist to verify your setup:
react-native/Libraries/*)Questions? Issues?
references/new-architecture-errors.md for build errorsreferences/react-19-migration.md for React 19 issuesKnowledge 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.
Weekly Installs
738
Repository
GitHub Stars
661
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
claude-code560
opencode543
gemini-cli538
codex498
antigravity438
cursor429
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
103,800 周安装
腾讯云CloudBase AI模型Web技能:前端调用混元/DeepSeek模型,实现流式文本生成
536 周安装
parallel-web-extract:并行网页内容提取工具,高效抓取网页数据
536 周安装
Rust调用关系图生成器 - 可视化函数调用层次结构,提升代码分析效率
536 周安装
web-fetch网页抓取工具:优先Markdown,智能选择器提取,Bun脚本备用
537 周安装
stock-watcher 自选股管理工具 - 实时股票行情监控与投资组合跟踪
537 周安装
质量不合格品管理NCR指南:FDA IATF AS9100 ISO 13485标准下的CAPA与根本原因分析
537 周安装
saturationcolorluminosity