Skip to content

Repository files navigation

Insight Pocket · 问答口袋

一个基于 Expo + React Native + TypeScript 的移动端问答阅读应用。 覆盖内容社区类产品最常见的前端场景:信息流、内容详情、评论、搜索、收藏,以及 AI 摘要的流式交互。

发现 Feed 问题详情 搜索 收藏

Expo SDK 52 React Native 0.76 TypeScript strict New Architecture


项目简介

Insight Pocket 是一个内容阅读类的移动端应用,模拟问答社区的核心体验。它不依赖真实后端,用结构化的本地数据驱动完整的交互流程,重点打磨移动端前端工程的几个关键面:

  • 长列表��能 —— 基于 FlatList 的虚拟化渲染、React.memo 与稳定引用优化
  • 流式交互 —— 一个与真实 SSE 接口同构的 AI 摘要状态机(idle → generating → done | error
  • 本地持久化 —— 收藏数据通过 AsyncStorage 落盘,并以 Context 跨页面同步
  • 完整的状态覆盖 —— 加载(骨架屏)、空状态、错误态、下拉刷新、上拉加载
  • 移动端适配 —— 安全区、软键盘、触摸反馈、浅色 / 深色主题

功能模块

页面 能力 入口文件
发现 Feed FlatList 长列表、下拉刷新、上拉加载更多、骨架屏占位 src/screens/FeedScreen.tsx
问题详情 长回答、评论列表、图片全屏预览、AI 摘要流式输出、收藏 src/screens/DetailScreen.tsx
搜索 TextInput + 300ms 防抖、热门搜索、加载态、空状态 src/screens/SearchScreen.tsx
收藏 AsyncStorage 本地持久化、跨页面同步、空状态 src/screens/FavoritesScreen.tsx
全局 浅色 / 深色主题切换、安全区适配、底部 Tab 导航 src/theme/src/navigation/

技术栈

类别 选型
框架 Expo SDK 52 / React Native 0.76(New Architecture / Fabric)
语言 TypeScript(strict 模式)
导航 React Navigation 7(Bottom Tabs + Native Stack)
持久化 @react-native-async-storage/async-storage
图片 expo-image(缓存与淡入过渡)
动画 Animated 实现骨架屏 shimmer,未引入额外动画库

架构设计

┌─────────────────────────────────────────────────────────────────────┐
│                              App.tsx                                  │
│   Provider 嵌套(外 → 内):                                          │
│   GestureHandlerRootView → SafeAreaProvider → ThemeProvider           │
│                                            → FavoritesProvider        │
│                                            → AppNavigator             │
└─────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      AppNavigator (Native Stack)                      │
│                                                                       │
│   ┌──────────────────────────────┐      ┌─────────────────────────┐  │
│   │   Tabs (Bottom Tab)          │ ───▶ │   Detail (Stack push)   │  │
│   │                              │      │   问题详情页             │  │
│   │  ┌────────┬────────┬──────┐  │      └─────────────────────────┘  │
│   │  │ Feed   │ Search │ Fav  │  │                                   │
│   │  │ 发现   │ 搜索   │ 收藏 │  │      header 右上角:🌙 主题切换    │
│   │  └────────┴────────┴──────┘  │                                   │
│   └──────────────────────────────┘                                   │
└─────────────────────────────────────────────────────────────────────┘
        │                    │                    │
        ▼                    ▼                    ▼
┌───────────────┐  ┌──────────────────┐  ┌────────────────────┐
│  Screens      │  │  Components       │  │  Hooks             │
│               │  │                   │  │                    │
│  FeedScreen   │  │  QuestionCard ◀───┼──┤  useFavorites      │
│  DetailScreen │  │  StreamingSummary │  │   (+ Context)      │
│  SearchScreen │  │  ImagePreview     │  │  useDebouncedValue │
│  Favorites    │  │  LoadingState     │  │  useStreamingSummary│
│               │  │  EmptyState       │  │                    │
│               │  │  Tag / Avatar     │  │                    │
│               │  │  ThemeToggle      │  │                    │
└───────────────┘  └──────────────────┘  └────────────────────┘
        │                    │                    │
        └────────────────────┴────────────────────┘
                             │
        ┌────────────────────┼────────────────────┐
        ▼                    ▼                    ▼
┌───────────────┐  ┌──────────────────┐  ┌────────────────────┐
│  Theme        │  │  Data             │  │  AsyncStorage      │
│  lightTheme   │  │  mockQuestions    │  │  (设备本地)         │
│  darkTheme    │  │  (8 条结构化数据) │  │  收藏 id 列表       │
│  ThemeContext │  │                   │  │                    │
└───────────────┘  └──────────────────┘  └────────────────────┘

两条核心数据流

  1. 收藏状态useFavoritesFavoritesProvider 中只实例化一次,通过 Context 下发给 Feed 卡片、详情页与收藏页;任意一处 toggleFavorite 都会写穿到 AsyncStorage,并让三处视图同步更新。

  2. 主题切换ThemeProvider 默认跟随系统 useColorScheme,同时支持手动覆盖。主题既下发给所有自定义组件,也桥接进 React Navigation 的容器主题,让导航栏与页面一起换肤。


目录结构

src/
  screens/         # 四个页面:Feed / Detail / Search / Favorites
  components/       # QuestionCard / Tag / EmptyState / LoadingState
                   # StreamingSummary / ImagePreview / Avatar / ThemeToggle
  hooks/           # useFavorites(+Context) / useDebouncedValue / useStreamingSummary
  navigation/      # Tab + Stack 导航与类型
  theme/           # 主题定义与 ThemeContext(含深色模式)
  data/            # mockQuestions 结构化数据
  types/           # Question / Comment 类型
  utils/           # 时间、数字格式化

工程亮点

列表性能 QuestionCardReact.memo 包裹,renderItem / keyExtractoruseCallback 固定引用,避免父组件重渲染时整列表被动更新。上拉加载用 loadingMore / hasMore 双 flag 拦截 onEndReached 的重复触发与触底���触,footer 明确区分「加载中」与「没有更多了」。

搜索防抖 useDebouncedValue 把输入值与实际过滤值解耦,输入停顿 300ms 才触发过滤。「正在输入但尚未触发」的窗口会显示 loading 提示,体验更贴近远程搜索;清空输入时立即清结果而非等待防抖。

AI 摘要流式 useStreamingSummary 是一个 idle → generating → done | error 状态机,当前以定时器逐字 append 模拟流式输出,但对外暴露的 status / text 接口与真实 SSE 完全一致——接入后端时只需替换数据源,消费 UI 无需改动。组件卸载时清理定时器,避免内存泄漏。

主题系统 ThemeContext 跟随系统并支持手动切换,亮 / 暗双主题集中定义;并桥接进导航容器主题,实现导航栏、背景、状态栏的整体换肤。


本地运行

npm install
npm start

然后任选其一:

  • 手机安装 Expo Go,扫描终端二维码
  • a 启动 Android 模拟器、i 启动 iOS 模拟器
  • w 在浏览器中预览

Android 安装包

每次推送 v* 标签时,GitHub Actions 会自动云端构建 Android APK 并发布到 Releases。可直接下载安装到 Android 设备体验。


界面预览

发现 Feed 问题详情 搜索 收藏 深色模式
Feed Detail Search Favorites Dark

设计边界

登录注册、真实后端、推荐算法、支付、即时通讯等不在本项目范围内——目标是把「内容消费」这条主线做扎实、做得贴近真实移动端产品的体验。

About

基于 Expo + React Native + TypeScript 的移动端问答阅读应用

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages