05 React Native架构设计、主线项目与专家实践

本章把 React Native 知识体系落到一个渐进式综合项目:Mobile Knowledge Hub。它从最小组件开始,逐步扩展到导航、状态管理、异步数据、离线缓存、权限、性能优化、新架构和发布体系。

1. 专家能力模型

层级 能力目标
入门 能写核心组件、样式、布局、基础交互
进阶 能处理导航、状态、表单、数据请求、设备能力
高级 能优化列表、动画、图片、启动、线程卡顿
精通 能建立 TypeScript、测试、调试、构建、发布体系
专家 能设计跨平台架构、离线同步、新架构迁移和长期演进

2. Mobile Knowledge Hub 背景

应用目标:

  • 展示 React Native 学习模块。
  • 支持搜索、层级筛选、收藏、完成状态。
  • 支持详情页。
  • 支持离线读取。
  • 支持推送学习提醒。
  • 支持统计学习进度。
  • 最终具备真实移动应用复杂度。

3. Stage 1:核心组件

jsx 复制代码
function LessonCard({ item, onPress }) {
  return (
    <Pressable style={styles.card} onPress={() => onPress(item.id)}>
      <Text style={styles.level}>{item.level}</Text>
      <Text style={styles.title}>{item.title}</Text>
      <Text style={styles.summary} numberOfLines={2}>
        {item.summary}
      </Text>
    </Pressable>
  );
}

训练点:

  • View
  • Text
  • Pressable
  • StyleSheet
  • 文本截断。
  • 移动端点击区域。

4. Stage 2:列表和筛选

jsx 复制代码
function LessonListScreen() {
  const [query, setQuery] = useState('');

  const visibleLessons = useMemo(() => {
    return lessons.filter((lesson) => lesson.title.includes(query));
  }, [query]);

  return (
    <View style={styles.screen}>
      <TextInput
        value={query}
        onChangeText={setQuery}
        placeholder="搜索知识点"
      />
      <FlatList
        data={visibleLessons}
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => <LessonCard item={item} />}
      />
    </View>
  );
}

训练点:

  • 受控输入。
  • FlatList
  • 派生数据。
  • 列表 key。

5. Stage 3:Reducer 状态模型

js 复制代码
const initialState = {
  query: '',
  level: '全部',
  favorites: [],
  completed: [],
};

function reducer(state, action) {
  switch (action.type) {
    case 'query-changed':
      return { ...state, query: action.query };
    case 'favorite-toggled':
      return {
        ...state,
        favorites: state.favorites.includes(action.id)
          ? state.favorites.filter((id) => id !== action.id)
          : [...state.favorites, action.id],
      };
    case 'completed-toggled':
      return {
        ...state,
        completed: state.completed.includes(action.id)
          ? state.completed.filter((id) => id !== action.id)
          : [...state.completed, action.id],
      };
    default:
      return state;
  }
}

6. Stage 4:导航

jsx 复制代码
function LessonsStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Lessons" component={LessonListScreen} />
      <Stack.Screen name="LessonDetail" component={LessonDetailScreen} />
    </Stack.Navigator>
  );
}

跳转:

jsx 复制代码
navigation.navigate('LessonDetail', { id: item.id });

详情页通过 ID 读取数据,不通过 params 传大对象。

7. Stage 5:服务端数据

jsx 复制代码
function useLessons() {
  return useQuery({
    queryKey: ['lessons'],
    queryFn: fetchLessons,
  });
}

Mutation:

jsx 复制代码
const mutation = useMutation({
  mutationFn: updateProgress,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['lessons'] });
  },
});

8. Stage 6:离线能力

离线策略:

  • 首次成功请求后缓存课程。
  • 收藏和完成状态本地保存。
  • 离线操作进入 outbox。
  • 恢复网络后同步。
  • 冲突时以服务端版本或用户确认策略处理。

Outbox 概念:

ts 复制代码
type OutboxAction =
  | { type: 'complete-lesson'; lessonId: string; createdAt: number }
  | { type: 'favorite-lesson'; lessonId: string; createdAt: number };

9. Stage 7:推送和提醒

能力:

  • 请求通知权限。
  • 注册设备 token。
  • 服务端保存 token。
  • 根据学习计划发送提醒。
  • 点击通知进入对应课程。

专家注意:

  • 权限拒绝要降级。
  • 通知点击要接入 Deep Link。
  • token 会变化,需要刷新。
  • iOS/Android 行为不同。

10. Stage 8:性能优化

项目中必须处理:

  • FlatList 参数。
  • LessonCard memo。
  • 图片尺寸和缓存。
  • 搜索防抖。
  • 导航后延迟重计算。
  • Release 包性能验证。
jsx 复制代码
const renderItem = useCallback(({ item }) => {
  return <LessonCard item={item} onPress={openDetail} />;
}, [openDetail]);

11. Stage 9:工程化

最终目录:

text 复制代码
src/
├── app/
│   ├── navigation/
│   └── providers/
├── features/
│   └── lessons/
│       ├── components/
│       ├── screens/
│       ├── model/
│       ├── services/
│       └── hooks/
├── shared/
│   ├── ui/
│   ├── theme/
│   ├── device/
│   └── api/
└── main.tsx

12. 架构边界

页面层:

  • 读取导航参数。
  • 组织屏幕布局。
  • 接入页面级数据。

Feature 层:

  • 业务组件。
  • Reducer。
  • Selector。
  • 业务 Hook。

Service 层:

  • API 请求。
  • 本地缓存。
  • 同步队列。

Shared 层:

  • 基础 UI。
  • theme。
  • device hooks。
  • 通用工具。

13. ADR 示例

md 复制代码
# ADR: Mobile Knowledge Hub 使用 Expo Dev Build

## 背景

应用需要推送、相机扫码、离线存储和少量原生 SDK。

## 决策

使用 Expo Development Build,保留 Expo 工具链,同时允许自定义原生能力。

## 后果

优点:构建和发布效率高,生态能力充足。
代价:需要理解 config plugin 和 EAS 构建流程。

14. 反模式

  • 长列表使用 ScrollView
  • route params 传复杂对象。
  • 把权限只放在客户端判断。
  • 忽略 Android 返回键。
  • 输入页不处理键盘遮挡。
  • 图片不设置尺寸。
  • 只在 Debug 包测试性能。
  • 任意引入未维护原生库。
  • 不上传 source map。
  • OTA 更新没有回滚策略。

15. Debug 顺序

页面异常:

  1. 数据是否正确。
  2. route params 是否正确。
  3. state 是否直接修改。
  4. FlatList key 是否稳定。
  5. 平台差异是否处理。

性能异常:

  1. Release 包是否复现。
  2. JS 线程是否阻塞。
  3. UI 线程是否掉帧。
  4. 列表是否过重。
  5. 图片是否过大。
  6. 原生模块是否频繁调用。

发布异常:

  1. 环境配置。
  2. 证书和签名。
  3. 原生权限配置。
  4. 版本号和 build number。
  5. 新架构兼容。

16. 专家检查清单

架构:

  • 模块依赖方向是否清晰?
  • 领域规则是否从 UI 抽离?
  • 离线同步是否有冲突策略?
  • Deep Link 是否覆盖关键路径?
  • 权限是否由服务端最终校验?

性能:

  • 长列表是否虚拟化?
  • 动画是否避免 JS 每帧驱动?
  • 图片是否有缩略图和缓存?
  • 首屏是否延迟低频模块?
  • Release 包是否验证?

工程:

  • TypeScript 是否覆盖导航参数?
  • E2E 是否覆盖关键路径?
  • 崩溃上报和 source map 是否接入?
  • OTA 是否有灰度和回滚?
  • Android/iOS 真机是否都测过?

专家判断:

  • 为什么选择 Expo 或 RN CLI?
  • 为什么这个状态不进全局 store?
  • 为什么这个模块需要原生能力?
  • 新架构迁移失败如何回退?
  • 当前方案 12 个月后还能否承载业务变化?

17. 移动端架构场景题

17.1 内容学习 App

特征:

  • 内容列表。
  • 播放或阅读。
  • 收藏和进度。
  • 离线缓存。

推荐:

  • Expo Dev Build。
  • TanStack Query。
  • 本地缓存和 outbox。
  • 推送提醒。
  • FlatList/FlashList。

17.2 高实时协作 App

特征:

  • WebSocket。
  • 本地草稿。
  • 冲突合并。
  • 弱网复杂。

推荐:

  • 明确 sync engine。
  • 操作日志。
  • 幂等 mutation。
  • 冲突策略。
  • 网络状态机。

17.3 重原生能力 App

特征:

  • 相机、蓝牙、地图、音视频、传感器。
  • 原生 SDK 多。

推荐:

  • RN CLI 或 Expo Dev Build。
  • Native Module 边界设计。
  • 原生团队参与。
  • 新架构兼容评估。

18. 离线优先架构

离线优先不是简单缓存。

需要:

  • 本地数据源。
  • 同步队列。
  • 冲突解决。
  • 后台同步。
  • UI 标记 pending。
  • 用户可理解的失败恢复。

状态模型:

ts 复制代码
type SyncStatus = 'synced' | 'pending' | 'failed';

type LocalLessonProgress = {
  lessonId: string;
  completed: boolean;
  syncStatus: SyncStatus;
  updatedAt: number;
};

19. 权限和隐私架构

专家级应用要设计:

  • 最小权限。
  • 延迟请求权限。
  • 权限用途说明。
  • 用户拒绝后的降级路径。
  • 隐私政策和商店声明一致。
  • 敏感数据加密存储。

权限不是按钮状态,而是产品流程。

20. 主线项目最终验收

入门:

  • 核心组件页面。
  • 样式和布局。
  • 搜索和列表。

进阶:

  • Stack/Tabs 导航。
  • Reducer 状态。
  • 数据请求。
  • 权限和设备状态。

高级:

  • FlatList 优化。
  • 图片优化。
  • 动画和手势。
  • AppState 和离线。

精通:

  • TypeScript。
  • 测试。
  • EAS/CI。
  • 崩溃监控。
  • OTA。

专家:

  • 新架构评估。
  • Native Module 边界。
  • 离线同步。
  • ADR。
  • 发布回滚。

21. React Native 专家总表

  • Core Components。
  • StyleSheet。
  • Flexbox。
  • Safe Area。
  • Platform。
  • TextInput。
  • FlatList。
  • SectionList。
  • Navigation。
  • Deep Link。
  • BackHandler。
  • Permissions。
  • AppState。
  • Linking。
  • AsyncStorage。
  • NetInfo。
  • KeyboardAvoidingView。
  • Animated。
  • Reanimated。
  • Gesture Handler。
  • Hermes。
  • Metro。
  • Fabric。
  • TurboModules。
  • JSI。
  • Codegen。
  • Expo。
  • EAS。
  • OTA。
  • Native crash。
  • Source maps。
  • Store release。
  • 离线同步。
  • 权限隐私。
  • 新架构迁移。

22. React Native 架构失败信号

  • 所有屏幕都直接请求接口。
  • 导航参数传完整业务对象。
  • 离线状态没有产品策略。
  • 原生模块 API 随业务页面变化。
  • 推送点击不能恢复正确页面。
  • Android/iOS 行为长期不一致。
  • 发布依赖某个人手工操作。
  • 崩溃日志无法映射源码。
  • OTA 版本和 native 版本不兼容。
  • 新架构升级没有回退计划。

23. 专家决策模板

text 复制代码
问题:
  当前移动端复杂度来自哪里?

约束:
  团队、时间、原生能力、发布要求、性能目标。

备选:
  Expo / Dev Build / RN CLI / Native。

决策:
  选择方案和原因。

风险:
  依赖、性能、发布、兼容、审核。

回退:
  如何关闭、降级或迁移。

24. Mobile Knowledge Hub 扩展路线

  • v1:本地课程列表、搜索、收藏。
  • v2:详情页、学习进度、Reducer。
  • v3:远程数据、缓存、刷新。
  • v4:离线 outbox、恢复同步。
  • v5:推送提醒、Deep Link。
  • v6:性能优化、FlashList、图片缓存。
  • v7:E2E、崩溃上报、OTA。
  • v8:新架构兼容和自定义 Native Module。

面试题完整答案总集:React Native 架构与专家实践

为什么选择 Expo、Dev Build、RN CLI 或 Native?

选择取决于原生能力复杂度、团队能力、发布要求和长期维护成本。普通业务应用优先 Expo;需要少量自定义原生能力用 Expo Dev Build;大量原生 SDK 或深度平台集成用 RN CLI;性能或平台体验要求极高的核心模块可考虑原生实现。

为什么这个状态不进全局 store?

如果状态只属于一个屏幕或 feature,全局 store 会扩大耦合和维护成本。移动端还要考虑导航生命周期、离线缓存和服务端状态。只有跨多个远距离屏幕共享、需要持久化或细粒度订阅时,才考虑全局 store。

为什么这个模块需要原生能力?

当 JS 和现有库无法满足平台 API、性能、安全、硬件或第三方 SDK 接入需求时,才需要原生模块。例如加密、生物识别、蓝牙、相机帧处理、音视频、地图 SDK。普通业务逻辑不应下沉到原生。

新架构迁移失败如何回退?

应在迁移前保留关闭 New Architecture 的构建配置,使用独立分支验证依赖兼容,CI 同时验证 iOS/Android 构建。失败时回退配置、锁定依赖版本、替换不兼容库,并通过 ADR 记录原因和后续计划。

当前方案 12 个月后还能否承载业务变化?

要评估模块边界、导航结构、状态分层、离线策略、发布流程、依赖治理和新架构兼容。如果业务增长后仍能按 feature 扩展、服务层清晰、测试覆盖关键路径、OTA 可回滚、原生能力有边界,就更能承载长期变化。

离线优先架构最关键的是什么?

关键是本地数据源、操作队列、同步协议和冲突解决,而不是简单缓存。每个离线操作都要有唯一 ID、状态、重试次数和时间戳;服务端接口要幂等;UI 要标记 pending/failed;恢复网络后要能安全同步。

权限和隐私架构如何设计?

遵循最小权限、延迟请求、用途说明、拒绝降级、敏感数据安全存储。权限不是技术弹窗,而是产品流程。服务端仍需做权限校验,客户端权限只决定能否调用设备能力。

React Native 专家和普通开发者的区别是什么?

普通开发者能写页面和调用库;专家能判断跨平台边界、性能瓶颈、原生依赖风险、发布和回滚策略、离线同步、权限隐私、新架构迁移成本,并能把这些决策文档化、可验证、可回退。

相关推荐
killerbasd11 小时前
还是迷茫 5.3
前端·react.js·前端框架
kyriewen12 小时前
代码写成一锅粥?3个设计模式让你的项目“起死回生”
前端·javascript·设计模式
不会敲代码113 小时前
从零搭建 AI 日记助手:用 Milvus 向量数据库实现语义搜索
javascript·openai
threelab14 小时前
Three.js UV 图像变换效果 | 三维可视化 / AI 提示词
javascript·人工智能·uv
竹林81815 小时前
用Viem替代ethers.js:从一次签名失败到完整迁移的实战记录
前端·javascript
不可能的是17 小时前
Claude Code 子 Agent 机制全解:怎么跑起来、怎么被管理、怎么互不干扰
javascript
HSunR17 小时前
dify 搭建ai作业批改流
开发语言·前端·javascript
代码不加糖17 小时前
2026 跨境电商独立站实战:从 0 到 1 搭建高转化 SaaS 商城(附源码)
开发语言·前端·javascript
江南十四行18 小时前
ReAct Agent 基本理论与项目实战(一)
前端·react.js·前端框架