Published on

expo项目架构文档

Authors
  • avatar
    Name
    刘十三
    Twitter

项目架构文档

基于 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 生成类型与请求客户端
UINativeWind / 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

架构与各层职责

ScreenHook/QueryService(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 再改调用处。