SuperAPI AI 工具集

expo-sdk

编程与开发

查看项目

更新于 10-16 10:55

技能介绍

Expo SDK 54+ 提供托管式 React Native 开发环境,包含基于文件的路由(Expo Router)、原生模块访问以及简化的构建工具链。本技能覆盖应用配置、根布局 Provider 模式以及关键 Expo/React Native 库的使用方式。

前置条件:使用 npx create-expo-app 创建项目,或在 package.json 中声明 Expo SDK 54+。

工作流

搭建新的 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. 使用 Provider 栈设置根布局
  5. 在 app.json 中配置 scheme、name、splash
  6. 添加路由组和页面
  7. 运行:pnpm start(Expo 开发服务器)

新增库时:

  1. 使用 pnpm 安装:pnpm add [library]
  2. 检查是否需要在 app.json 中配置 Expo config plugin
  3. 若添加了原生模块,需重新构建开发客户端:npx expo prebuild

app.json 配置 演示应用的关键字段:

  • expo.name:显示名称
  • expo.slug:URL 安全标识符
  • expo.scheme:深链 scheme(例如 myapp)
  • expo.orientation:portrait(演示应用的默认值)
  • expo.splash:启动屏配置
  • expo.ios.bundleIdentifier:iOS bundle ID
  • expo.android.package:Android 包名
  • expo.plugins:Expo 配置插件(例如 expo-router)

根布局 Provider 模式 根 app/_layout.tsx 使用 Provider 包裹整个应用。标准嵌套顺序: GestureHandlerRootView (flex: 1) └── SafeAreaProvider └── ThemeProvider / Context └── Stack (Expo Router)

  • GestureHandlerRootView 必须位于最外层(手势处理与底部弹层的要求)
  • SafeAreaProvider 为所有后代提供安全区域 inset
  • 应用级 Context Provider 放在 SafeAreaProvider 与 Stack 之间
  • 自定义头部时使用 <Stack screenOptions={{ headerShown: false }} />

expo-image(替代 RN Image) 所有图片渲染都应使用 expo-image,它提供缓存、blurhash 占位符、内容适配模式和动画过渡。关键 props:

  • source:URI 字符串或本地图片的 require()
  • placeholder:加载状态使用的 blurhash 字符串
  • contentFit:'cover' | 'contain' | 'fill'
  • transition:淡入时长(毫秒,例如 300)

expo-haptics 为交互提供触觉反馈:

  • Haptics.selectionAsync():用于选择、开关的轻触
  • Haptics.impactAsync(ImpactFeedbackStyle.Medium):按钮按下、卡片点击
  • Haptics.notificationAsync(NotificationFeedbackType.Success):操作完成 应克制使用——每次触摸都触发触觉反馈会令人反感。

安全区域 inset 处理设备刘海、状态栏和 Home 指示器:

  • useSafeAreaInsets():返回以点为单位的 { top, bottom, left, right }
  • 应用于屏幕容器:paddingTop: insets.top
  • NativeWind 类名:使用 pt-[${insets.top}px] 或用 SafeAreaView 包裹

@gorhom/bottom-sheet 替代 Radix Dialog 的移动端模态模式:

  • 用于详情视图、选择、筛选、表单
  • 定义吸附点:snapPoints={['25%', '50%', '90%']}
  • 背景遮罩:backdropComponent 配合点击关闭
  • 弹层内可滚动内容使用 BottomSheetScrollView
  • 需要 GestureHandlerRootView 作为祖先节点

FlashList(替代 FlatList) 来自 @shopify/flash-list 的高性能列表渲染:

  • 可直接替换 FlatList,但必须提供 estimatedItemSize
  • estimatedItemSize={80}:每项估算高度(点)
  • 复用架构以实现流畅的 60fps 滚动
  • 使用 contentContainerClassName 进行 NativeWind 样式设置

lucide-react-native React Native 图标库(与 Web 端 lucide-react 对应):

  • 按需导入图标:import { Home, Settings, ChevronRight } from 'lucide-react-native'
  • Props:size、color、strokeWidth
  • 在移动端和 Web 代码库之间保持图标集一致

StatusBar 按屏幕配置状态栏外观:

  • 浅色背景使用 <StatusBar style="dark" />
  • 深色背景使用 <StatusBar style="light" />
  • 从 expo-status-bar 导入

最佳实践

  • 用 style={{ flex: 1 }} 的 GestureHandlerRootView 包裹根布局
  • 所有图片使用 expo-image(缓存、blurhash、性能)
  • 仅为主要操作添加触觉反馈(按钮、重要选择),而非每次触摸
  • 为所有 FlashList 组件设置 estimatedItemSize
  • Provider 放在根 _layout.tsx,而非各个屏幕中
  • 手动内边距使用 useSafeAreaInsets(),简单包裹使用 SafeAreaView
  • 在真机上测试触觉反馈和性能

反模式

  • 使用 React Native Image 而非 expo-image
  • 大数据集使用 FlatList 而非 FlashList
  • 忘记 GestureHandlerRootView(会导致底部弹层和手势崩溃)
  • 每次交互都过度使用触觉反馈
  • 硬编码状态栏高度而非使用安全区域 inset
  • FlashList 缺少 estimatedItemSize(必填 prop,会有控制台警告)
  • 将 SafeAreaView 放在 ScrollView 内部(导致布局问题)
  • 未在 app.json 的 plugins 数组中包含 expo-router 插件