expo-sdk

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Expo SDK

Expo SDK

Overview

概述

Expo SDK 54+ provides a managed React Native development environment with file-based routing (Expo Router), native module access, and streamlined build tooling. This skill covers app configuration, the root layout provider pattern, and key Expo/RN libraries.
Prerequisite:
npx create-expo-app
or Expo SDK 54+ in
package.json
Expo SDK 54+ 提供了一个托管式React Native开发环境,支持基于文件的路由(Expo Router)、原生模块访问以及简化的构建工具链。本技能涵盖应用配置、根布局提供者模式,以及关键的Expo/RN库。
前置条件:使用
npx create-expo-app
创建项目,或
package.json
中已包含Expo SDK 54+

Workflows

工作流程

Setting up a new Expo demo:
  1. Create project:
    npx create-expo-app [demo-name] --template blank-typescript
  2. Install core dependencies:
    pnpm add expo-router expo-image expo-haptics react-native-reanimated react-native-gesture-handler react-native-safe-area-context @gorhom/bottom-sheet @shopify/flash-list lucide-react-native nativewind tailwindcss@3
  3. Configure NativeWind (see
    nativewind
    skill)
  4. Set up root layout with provider stack
  5. Configure
    app.json
    with scheme, name, splash
  6. Add route groups and screens
  7. Run:
    pnpm start
    (Expo dev server)
Adding a new library:
  1. Install with pnpm:
    pnpm add [library]
  2. Check if Expo config plugin needed in
    app.json
  3. Rebuild dev client if native module added:
    npx expo prebuild
搭建新的Expo演示项目:
  1. 创建项目:
    npx create-expo-app [demo-name] --template blank-typescript
  2. 安装核心依赖:
    pnpm add expo-router expo-image expo-haptics react-native-reanimated react-native-gesture-handler react-native-safe-area-context @gorhom/bottom-sheet @shopify/flash-list lucide-react-native nativewind tailwindcss@3
  3. 配置NativeWind(参考
    nativewind
    相关技能)
  4. 设置带有提供者栈的根布局
  5. app.json
    中配置scheme、名称、启动页
  6. 添加路由组和页面
  7. 运行:
    pnpm start
    (Expo开发服务器)
添加新库:
  1. 使用pnpm安装:
    pnpm add [library]
  2. 检查是否需要在
    app.json
    中添加Expo配置插件
  3. 如果添加了原生模块,重新构建开发客户端:
    npx expo prebuild

Guidance

指南

app.json Configuration

app.json配置

Key fields for demo apps:
FieldPurpose
expo.name
Display name
expo.slug
URL-safe identifier
expo.scheme
Deep link scheme (e.g.,
myapp
)
expo.orientation
portrait
(default for demos)
expo.splash
Splash screen configuration
expo.ios.bundleIdentifier
iOS bundle ID
expo.android.package
Android package name
expo.plugins
Expo config plugins (e.g.,
expo-router
)
演示项目的关键字段:
字段用途
expo.name
显示名称
expo.slug
URL安全的标识符
expo.scheme
深度链接协议(例如:
myapp
expo.orientation
屏幕方向(演示项目默认
portrait
即竖屏)
expo.splash
启动屏配置
expo.ios.bundleIdentifier
iOS包标识符
expo.android.package
Android包名
expo.plugins
Expo配置插件(例如:
expo-router

Root Layout Provider Pattern

根布局提供者模式

The root
app/_layout.tsx
wraps the entire app with providers. Standard order:
GestureHandlerRootView (flex: 1)
  └── SafeAreaProvider
       └── ThemeProvider / Context
            └── Stack (Expo Router)
  • GestureHandlerRootView
    must be outermost (required by gesture handler and bottom sheets)
  • SafeAreaProvider
    provides safe area insets to all descendants
  • App-level context providers go between SafeAreaProvider and Stack
  • <Stack screenOptions={{ headerShown: false }} />
    for custom headers
根目录下的
app/_layout.tsx
会用提供者包裹整个应用。标准顺序:
GestureHandlerRootView (flex: 1)
  └── SafeAreaProvider
       └── ThemeProvider / Context
            └── Stack (Expo Router)
  • GestureHandlerRootView
    必须是最外层(手势处理器和底部弹窗的要求)
  • SafeAreaProvider
    为所有子组件提供安全区域内边距
  • 应用级别的上下文提供者应放在SafeAreaProvider和Stack之间
  • 使用
    <Stack screenOptions={{ headerShown: false }} />
    来自定义头部

expo-image (replaces RN Image)

expo-image(替代RN Image)

Use
expo-image
for all image rendering — provides caching, blurhash placeholders, content-fit modes, and animated transitions.
Key props:
  • source
    — URI string or require() for local images
  • placeholder
    — blurhash string for loading state
  • contentFit
    'cover'
    |
    'contain'
    |
    'fill'
  • transition
    — fade-in duration in ms (e.g.,
    300
    )
所有图片渲染都使用
expo-image
——它提供缓存、blurhash占位符、内容适配模式以及动画过渡效果。
关键属性:
  • source
    —— URI字符串或本地图片的require()引用
  • placeholder
    —— 加载状态下的blurhash字符串
  • contentFit
    ——
    'cover'
    |
    'contain'
    |
    'fill'
  • transition
    —— 淡入动画时长(单位:毫秒,例如
    300

expo-haptics

expo-haptics

Provide tactile feedback on interactions:
  • Haptics.selectionAsync()
    — light tap for selections, toggles
  • Haptics.impactAsync(ImpactFeedbackStyle.Medium)
    — button press, card tap
  • Haptics.notificationAsync(NotificationFeedbackType.Success)
    — action completion
Use sparingly — haptics on every touch is annoying.
为交互提供触觉反馈:
  • Haptics.selectionAsync()
    —— 轻触反馈,适用于选择、切换操作
  • Haptics.impactAsync(ImpactFeedbackStyle.Medium)
    —— 按钮按压、卡片点击时的反馈
  • Haptics.notificationAsync(NotificationFeedbackType.Success)
    —— 操作完成时的反馈
注意适度使用——每次触摸都触发触觉反馈会很烦人。

Safe Area Insets

安全区域内边距

Account for device notch, status bar, and home indicator:
  • useSafeAreaInsets()
    — returns
    { top, bottom, left, right }
    in points
  • Apply to screen containers:
    paddingTop: insets.top
  • NativeWind classes: use
    pt-[${insets.top}px]
    or wrap in SafeAreaView
适配设备的刘海、状态栏和Home指示器:
  • useSafeAreaInsets()
    —— 返回
    { top, bottom, left, right }
    (单位:点)
  • 应用到屏幕容器:
    paddingTop: insets.top
  • NativeWind类:使用
    pt-[${insets.top}px]
    或包裹在SafeAreaView中

@gorhom/bottom-sheet

@gorhom/bottom-sheet

Replaces Radix Dialog for mobile modal patterns:
  • Use for detail views, selections, filters, forms
  • Define snap points:
    snapPoints={['25%', '50%', '90%']}
  • Backdrop:
    backdropComponent
    with press-to-dismiss
  • BottomSheetScrollView
    for scrollable content inside sheets
  • Requires
    GestureHandlerRootView
    as ancestor
替代Radix Dialog的移动端模态框方案:
  • 适用于详情页、选择器、筛选器、表单
  • 定义吸附点:
    snapPoints={['25%', '50%', '90%']}
  • 背景层:使用
    backdropComponent
    实现点击关闭
  • BottomSheetScrollView
    用于弹窗内的可滚动内容
  • 要求祖先组件包含
    GestureHandlerRootView

FlashList (replaces FlatList)

FlashList(替代FlatList)

High-performance list rendering from
@shopify/flash-list
:
  • Drop-in FlatList replacement with mandatory
    estimatedItemSize
    prop
  • estimatedItemSize={80}
    — estimated height of each item in points
  • Recycling architecture for smooth 60fps scrolling
  • Use
    contentContainerClassName
    for NativeWind styling
来自
@shopify/flash-list
的高性能列表渲染组件:
  • 可直接替换FlatList,但必须传入
    estimatedItemSize
    属性
  • estimatedItemSize={80}
    —— 预估每个列表项的高度(单位:点)
  • 采用回收架构,实现60fps流畅滚动
  • 使用
    contentContainerClassName
    进行NativeWind样式设置

lucide-react-native

lucide-react-native

Icon library for React Native (matches web lucide-react):
  • Import individual icons:
    import { Home, Settings, ChevronRight } from 'lucide-react-native'
  • Props:
    size
    ,
    color
    ,
    strokeWidth
  • Consistent icon set across mobile and web codebases
React Native的图标库(与web端lucide-react保持一致):
  • 导入单个图标:
    import { Home, Settings, ChevronRight } from 'lucide-react-native'
  • 属性:
    size
    color
    strokeWidth
  • 在移动端和web端代码库中使用统一的图标集

StatusBar

StatusBar

Configure status bar appearance per screen:
  • <StatusBar style="dark" />
    for light backgrounds
  • <StatusBar style="light" />
    for dark backgrounds
  • Import from
    expo-status-bar
为每个页面配置状态栏外观:
  • 浅色背景下使用
    <StatusBar style="dark" />
  • 深色背景下使用
    <StatusBar style="light" />
  • expo-status-bar
    导入

Best Practices

最佳实践

  • Wrap root layout in
    GestureHandlerRootView
    with
    style={{ flex: 1 }}
  • Use expo-image for all images (caching, blurhash, performance)
  • Add haptics to primary actions only (buttons, major selections) — not every touch
  • Set
    estimatedItemSize
    on all FlashList components
  • Place providers in root
    _layout.tsx
    , not in individual screens
  • Use
    useSafeAreaInsets()
    for manual padding,
    SafeAreaView
    for simple wrapping
  • Test on real device for haptics and performance verification
  • GestureHandlerRootView
    包裹根布局,并设置
    style={{ flex: 1 }}
  • 所有图片都使用expo-image(缓存、blurhash、性能更优)
  • 仅为主要操作(按钮、重要选择)添加触觉反馈——不要每个触摸都加
  • 为所有FlashList组件设置
    estimatedItemSize
  • 将提供者放在根目录的
    _layout.tsx
    中,而非单个页面
  • 手动设置内边距时使用
    useSafeAreaInsets()
    ,简单包裹时使用SafeAreaView
  • 在真实设备上测试触觉反馈和性能

Anti-Patterns

反模式

  • Using React Native
    Image
    instead of
    expo-image
  • Using
    FlatList
    for large datasets instead of
    FlashList
  • Forgetting
    GestureHandlerRootView
    (causes bottom sheet and gesture crashes)
  • Overusing haptics on every interaction
  • Hardcoding status bar height instead of using safe area insets
  • Missing
    estimatedItemSize
    on FlashList (required prop, console warning)
  • Placing
    SafeAreaView
    inside ScrollView (causes layout issues)
  • Not including
    expo-router
    plugin in
    app.json
    plugins array
  • 使用React Native的
    Image
    而非
    expo-image
  • 处理大型数据集时使用
    FlatList
    而非
    FlashList
  • 忘记添加
    GestureHandlerRootView
    (会导致底部弹窗和手势崩溃)
  • 过度使用触觉反馈,每个交互都触发
  • 硬编码状态栏高度,而非使用安全区域内边距
  • FlashList未设置
    estimatedItemSize
    (必填属性,控制台会发出警告)
  • 在ScrollView内部放置
    SafeAreaView
    (会导致布局问题)
  • app.json
    的plugins数组中未包含
    expo-router
    插件