React Native & Expo Development Guide
A practical guide for building production-ready React Native and Expo applications. Covers UI, animations, state, testing, performance, and deployment.
References
Consult these resources as needed:
- - references/navigation.md — Expo Router: Stack, Tabs, NativeTabs (
headerLargeTitle, headerBackButtonDisplayMode), links, modals, sheets, context menus - references/components.md — FlashList patterns,
expo-image, safe areas (contentInsetAdjustmentBehavior), native controls, blur/glass effects, storage - references/styling.md — StyleSheet, NativeWind/Tailwind, platform styles, theming, dark mode
- references/animations.md — Reanimated 3: entering/exiting, shared values, gestures, scroll-driven
- references/state-management.md — Zustand (selectors, persist), Jotai (atoms, derived), React Query, Context
- references/forms.md — React Hook Form + Zod: validation, multi-step, dynamic arrays
- references/networking.md — fetch wrapper, React Query (optimistic updates), auth tokens, offline, API routes, webhooks
- references/performance.md — Profiling workflow, FlashList +
memo, bundle analysis, TTI, memory leaks, animation perf - references/testing.md — Jest, React Native Testing Library, E2E with Maestro
- references/native-capabilities.md — Camera, location, permissions (
use*Permissions hooks), haptics, notifications, biometrics - references/engineering.md — Project layout (
components/ui/, stores/, services/), path aliases, SDK upgrades, EAS build/submit, CI/CD, DOM components
Quick Reference
Component Preferences
| Purpose | Use | Instead of |
|---|
| Lists | INLINECODE9 (@shopify/flash-list) + memo items | INLINECODE12 (no view recycling) |
| Images |
expo-image | RN
<Image> (no cache, no WebP) |
| Press |
Pressable |
TouchableOpacity (legacy) |
| Audio |
expo-audio |
expo-av (deprecated) |
| Video |
expo-video |
expo-av (deprecated) |
| Animations | Reanimated 3 | RN Animated API (limited) |
| Gestures | Gesture Handler | PanResponder (legacy) |
| Platform check |
process.env.EXPO_OS |
Platform.OS |
| Context |
React.use() |
React.useContext() (React 18) |
| Safe area scroll |
contentInsetAdjustmentBehavior="automatic" |
<SafeAreaView> |
| SF Symbols |
expo-image with
source="sf:name" |
expo-symbols |
Scaling Up
| Situation | Consider |
|---|
| Long lists with scroll jank | Virtualized list libraries (e.g. FlashList) |
| Want Tailwind-style classes |
NativeWind v4 |
| High-frequency storage reads | Sync-based storage (e.g. MMKV) |
| New project with Expo | Expo Router over bare React Navigation |
State Management
| State Type | Solution |
|---|
| Local UI state | INLINECODE30 / INLINECODE31 |
| Shared app state |
Zustand or Jotai |
| Server / async data | React Query |
| Form state | React Hook Form + Zod |
Performance Priorities
| Priority | Issue | Fix |
|---|
| CRITICAL | Long list jank | INLINECODE32 + memoized items |
| CRITICAL |
Large bundle | Avoid barrel imports, enable R8 |
| HIGH | Too many re-renders | Zustand selectors, React Compiler |
| HIGH | Slow startup | Disable bundle compression, native nav |
| MEDIUM | Animation drops | Only animate
transform/
opacity |
New Project Init
CODEBLOCK0
Then configure:
- 1. Set entry point in
package.json: INLINECODE36 - Add scheme in
app.json: INLINECODE38 - Delete
App.tsx and INLINECODE40 - Create
app/_layout.tsx as root Stack layout - Create
app/(tabs)/_layout.tsx for tab navigation - Create route files in
app/(tabs)/ (see navigation.md)
For web support, also install: INLINECODE44
Core Principles
Consult references before writing: when implementing navigation, lists, networking, or project setup, read the matching reference file above for patterns and pitfalls.
Try Expo Go first (npx expo start). Custom builds (eas build) only needed when using local Expo modules, Apple targets, or third-party native modules not in Expo Go.
Conditional rendering: use {count > 0 && <Text />} not {count && <Text />} (renders "0").
Animation rule: only animate transform and opacity — GPU-composited, no layout thrash.
Imports: always import directly from source, not barrel files — avoids bundle bloat.
Lists and images: before using FlatList or RN Image, check the Component Preferences table above — FlashList and expo-image are almost always the right choice.
Route files: always use kebab-case, never co-locate components/types/utils in app/.
Checklist
New Project Setup
- - [ ]
tsconfig.json path aliases configured - [ ]
EXPO_PUBLIC_API_URL env var set per environment - [ ] Root layout has
GestureHandlerRootView (if using gestures) - [ ]
contentInsetAdjustmentBehavior="automatic" on all scroll views - [ ]
FlashList instead of FlatList for lists > 20 items
Before Shipping
- - [ ] Profile in
--profile mode, fix frames > 16ms - [ ] Bundle analyzed (
source-map-explorer), no barrel imports - [ ] R8 enabled for Android
- [ ] Unit + component tests for critical paths
- [ ] E2E flows for login, core feature, checkout
Flutter development → see
flutter-dev skill.
iOS native (UIKit/SwiftUI) → see
ios-application-dev skill.
Android native (Kotlin/Compose) → see
android-native-dev skill.
React Native is a trademark of Meta Platforms, Inc. Expo is a trademark of 650 Industries, Inc. All other product names are trademarks of their respective owners.
React Native & Expo 开发指南
构建生产级 React Native 和 Expo 应用的实用指南。涵盖 UI、动画、状态管理、测试、性能优化和部署。
参考文档
根据需要查阅以下资源:
快速参考
组件选择偏好
| 用途 | 推荐使用 | 替代方案 |
|---|
| 列表 | FlashList(@shopify/flash-list)+ memo 项 | FlatList(无视图回收) |
| 图片 |
expo-image | RN
(无缓存、不支持 WebP) |
| 点击 | Pressable | TouchableOpacity(已过时) |
| 音频 | expo-audio | expo-av(已弃用) |
| 视频 | expo-video | expo-av(已弃用) |
| 动画 | Reanimated 3 | RN Animated API(功能有限) |
| 手势 | Gesture Handler | PanResponder(已过时) |
| 平台检测 | process.env.EXPO_OS | Platform.OS |
| 上下文 | React.use() | React.useContext()(React 18) |
| 安全区域滚动 | contentInsetAdjustmentBehavior=automatic | |
| SF Symbols | 使用 source=sf:name 的 expo-image | expo-symbols |
扩展方案
| 场景 | 考虑方案 |
|---|
| 长列表滚动卡顿 | 虚拟化列表库(如 FlashList) |
| 需要 Tailwind 样式类 |
NativeWind v4 |
| 高频存储读取 | 基于同步的存储(如 MMKV) |
| 使用 Expo 的新项目 | 优先使用 Expo Router 而非裸 React Navigation |
状态管理
| 状态类型 | 解决方案 |
|---|
| 本地 UI 状态 | useState / useReducer |
| 共享应用状态 |
Zustand 或 Jotai |
| 服务器/异步数据 | React Query |
| 表单状态 | React Hook Form + Zod |
性能优化优先级
| 优先级 | 问题 | 修复方案 |
|---|
| 关键 | 长列表卡顿 | FlashList + 记忆化项 |
| 关键 |
包体积过大 | 避免桶导入,启用 R8 |
| 高 | 过多重渲染 | Zustand 选择器、React Compiler |
| 高 | 启动缓慢 | 禁用包压缩、原生导航 |
| 中 | 动画掉帧 | 仅动画化 transform/opacity |
新项目初始化
bash
1. 创建项目
npx create-expo-app@latest my-app --template blank-typescript
cd my-app
2. 安装 Expo Router + 核心依赖
npx expo install expo-router react-native-safe-area-context react-native-screens
3. (可选)常用额外依赖
npx expo install expo-image react-native-reanimated react-native-gesture-handler
然后进行配置:
- 1. 在 package.json 中设置入口点:main: expo-router/entry
- 在 app.json 中添加 scheme:scheme: my-app
- 删除 App.tsx 和 index.ts
- 创建 app/layout.tsx 作为根堆栈布局
- 创建 app/(tabs)/layout.tsx 用于标签导航
- 在 app/(tabs)/ 中创建路由文件(参见 navigation.md)
如需支持 Web,还需安装:npx expo install react-native-web react-dom @expo/metro-runtime
核心原则
实现前查阅参考文档:在实现导航、列表、网络请求或项目设置时,先阅读上述对应的参考文件,了解模式和注意事项。
优先尝试 Expo Go(npx expo start)。仅在需要使用本地 Expo 模块、Apple 目标或 Expo Go 中不包含的第三方原生模块时,才需要自定义构建(eas build)。
条件渲染:使用 {count > 0 && } 而非 {count && }(后者会渲染出 0)。
动画规则:仅动画化 transform 和 opacity — GPU 合成,不会引起布局抖动。
导入规则:始终从源文件直接导入,而非桶文件 — 避免包体积膨胀。
列表和图片:在使用 FlatList 或 RN Image 之前,先查看上方的组件选择偏好表 — FlashList 和 expo-image 几乎总是正确的选择。
路由文件:始终使用短横线命名法(kebab-case),切勿在 app/ 中放置组件/类型/工具函数。
检查清单
新项目设置
- - [ ] 配置 tsconfig.json 路径别名
- [ ] 按环境设置 EXPOPUBLICAPI_URL 环境变量
- [ ] 根布局包含 GestureHandlerRootView(如果使用手势)
- [ ] 所有滚动视图设置 contentInsetAdjustmentBehavior=automatic
- [ ] 超过 20 项的列表使用 FlashList 而非 FlatList
发布前检查
- - [ ] 在 --profile 模式下进行性能分析,修复超过 16ms 的帧
- [ ] 进行打包分析(source-map-explorer),无桶导入
- [ ] Android 启用 R8
- [ ] 关键路径的单元测试 + 组件测试
- [ ] 登录、核心功能、结账的端到端测试流程
Flutter 开发 → 参见 flutter-dev 技能。
iOS 原生(UIKit/SwiftUI)→ 参见 ios-application-dev 技能。
Android 原生(Kotlin/Compose)→ 参见 android-native-dev 技能。
React Native 是 Meta Platforms, Inc. 的商标。Expo 是 650 Industries, Inc. 的商标。所有其他产品名称均为其各自所有者的商标。