- Published on
expo项目架构文档
- Authors

- Name
- 刘十三
项目架构文档
基于 Expo(React Native)的分层架构,文件路由(expo-router),面向多端(iOS/Android/Web)。
目录
技术栈
| 类别 | 技术 | 说明 |
|---|---|---|
| 框架 | Expo | 最新 SDK |
| 语言 | TypeScript | 严格模式 |
| 路由 | expo-router | 文件路由、Stack/Tabs |
| 状态 | Zustand / Jotai | 轻量全局状态 |
| 请求 | fetch + react-query / TanStack Query | 服务端状态与缓存 |
| API 生成 | openapi-typescript-codegen / orq / swagger-typescript-api | 基于 Swagger URL 或 JSON 生成类型与请求客户端 |
| UI | NativeWind / Tamagui / 自定义 | 样式方案 |
| 其他 | expo-constants, expo-secure-store, expo-updates | 配置、存储、OTA |
项目结构
your_app/
├── app/ # 路由(expo-router)
│ ├── _layout.tsx # 根布局
│ ├── (tabs)/ # Tab 分组
│ │ ├── _layout.tsx
│ │ ├── index.tsx
│ │ └── profile.tsx
│ ├── (stack)/ # Stack 分组
│ │ └── detail/[id].tsx
│ └── +not-found.tsx
│
├── components/ # 通用组件
│ ├── ui/ # 基础 UI
│ └── business/ # 业务组件
│
├── hooks/ # 自定义 Hooks
├── services/ # API 与业务接口
│ ├── api/ # 请求封装、baseURL、拦截器
│ ├── generated/ # Swagger 生成的 API 客户端与类型(勿手改)
│ └── xxx/ # 按领域封装,可调用 generated
│
├── store/ # 全局状态(Zustand 等)
├── types/ # 业务自定义类型(与 generated 互补)
├── utils/ # 工具函数
├── constants/ # 常量、主题
├── assets/
├── app.json
├── package.json
└── tsconfig.json
架构与各层职责
Screen → Hook/Query → Service(API) → 后端
↓
Store(全局状态)
- app/:页面入口,仅做布局与组合;数据通过 hooks 或 react-query 获取。
- components/:无业务状态的展示组件放
ui/;依赖业务类型的放business/。 - hooks/:封装复用逻辑(如 useAuth、useUser)、组合 react-query。
- services/:封装 HTTP 调用、请求/响应类型;不直接操作 UI。
- store/:全局状态(用户信息、主题、全局 UI 状态等)。
- types/:请求/响应、实体、路由参数等 TypeScript 类型。
页面示例(app)
// app/(tabs)/index.tsx
import { useUserList } from '@/hooks/useUserList';
export default function HomeScreen() {
const { data, isLoading, error } = useUserList();
if (isLoading) return <Loading />;
if (error) return <ErrorView error={error} />;
return <UserList list={data} />;
}
Hook 示例(组合 Service + Query)
// hooks/useUserList.ts
import { useQuery } from '@tanstack/react-query';
import { userService } from '@/services/user';
export function useUserList() {
return useQuery({
queryKey: ['user', 'list'],
queryFn: () => userService.getList(),
});
}
Service 示例
// services/user/index.ts
import { api } from '@/services/api';
import type { UserListResponse } from '@/types/user';
export const userService = {
async getList(): Promise<UserListResponse> {
const res = await api.get<UserListResponse>('/user/list');
return res.data;
},
};
状态与数据流
- 服务端状态:列表、详情等由 react-query 管理(cache、refetch、mutation)。
- 全局客户端状态:登录态、主题、语言等放 store(Zustand),按模块分 slice。
- 本地 UI 状态:表单、弹窗等用 useState/useReducer,复杂表单可用 react-hook-form。
开发规范
- 命名:组件 PascalCase;hooks 以 use 开头;services 小驼峰;类型/接口 PascalCase,请求/响应可加 Request/Response 后缀。
- 文件:组件与 hook 各占文件,与名称一致(UserCard.tsx、useUserList.ts)。
- 类型:请求/响应、实体统一放在 types/,在 services 与 components 中引用。
- 路由:app/ 下按 (group) 与文件约定路由,动态段用 [id].tsx;避免在组件内硬编码 path。
- 样式:选定一套方案(NativeWind/Tamagui/StyleSheet)后统一,避免混用多种体系。
快速开始
git clone <repo>
cd your_app
yarn install
yarn start
# 或 yarn ios / yarn android / yarn web
脚本命令
| 命令 | 说明 |
|---|---|
yarn start | 启动开发服务器 |
yarn ios | 跑 iOS 模拟器 |
yarn android | 跑 Android 模拟器 |
yarn web | 跑 Web |
yarn build:ios / build:android | 构建生产包 |
yarn lint | 执行 ESLint |
yarn typecheck | 执行 tsc 类型检查 |
yarn generate:api | 根据 Swagger 生成 API(见下节) |
基于 Swagger 生成 API
- 输入:后端 Swagger JSON URL(如
https://api.example.com/swagger/doc.json)或本地 JSON 文件。 - 输出:
services/generated/下的请求函数与 TypeScript 类型,不提交到业务手写逻辑,仅作为生成产物。
推荐方案一:openapi-typescript-codegen
yarn add -D openapi-typescript-codegen
package.json 脚本示例:
"generate:api": "openapi --input https://api.example.com/swagger/doc.json --output ./services/generated --client fetch"
或使用本地 JSON:
"generate:api": "openapi --input ./swagger.json --output ./services/generated --client fetch"
推荐方案二:orq(基于 fetch + 与后端约定一致)
yarn add -D orq
"generate:api": "orq https://api.example.com/swagger/doc.json -o ./services/generated"
使用约定
- 后端 Swagger 更新后执行
yarn generate:api再开发;生成的services/generated/可被services/xxx/或 hooks 直接引用。 - 若需统一 baseURL、鉴权、拦截器,可在
services/api/中封装一层,让 generated 的 client 使用该实例(具体以所用生成器的配置为准)。
AI 开发指南
- 页面仅写在 app/ 下,按 expo-router 约定;业务逻辑放 hooks 与 services。
- API:优先用 Swagger URL 或 JSON 执行
yarn generate:api生成services/generated/;业务封装在services/xxx/中调用 generated,或在 hooks 中组合 react-query。仅无 Swagger 的接口在 types/ + services 手写。 - 组件:无状态展示放 components/ui,依赖业务类型放 components/business;通过 props 与类型约束。
- 全局状态:在 store/ 中按模块定义,避免在页面内散落 useState 做跨屏共享。
- 命名与类型规范见上文;后端 Swagger 变更后先跑 generate:api 再改调用处。