React TypeScript 开发
文件架构
我们强制规定使用规范的文件目录结构。
CRA Project
|-- .gitignore # Git Ignore
|-- .prettierrc # Prettier 语法配置
|-- package.json # 依赖定义文件
|-- README.md # 项目说明
|-- tsconfig.json # TypeScript 配置
|-- yarn.lock # 依赖版本定义文件
|-- .github # GitHub 配置
| |-- ...
|-- .idea # Idea 配置(应被写入 ignore 文件)
|-- public # 公开文件
| |-- favicon.ico # 必须放置 ico 文件
| |-- ...
|-- src
|-- App.tsx # 路由配置和全局配置
|-- index.tsx # 主要组件、Provider 配置
|-- react-app-env.d.ts
|-- reportWebVitals.ts # 统计配置
|-- setupProxy.js # 开发时后端接口代理配置
|-- setupTests.ts # 测试配置
|-- components # 组件库
| |-- Uploader # 单一组件
| | |-- index.tsx # 组件默认导出
| | |-- ...
| |-- Layout # 样式组件
| |-- Admin # 部分组件库
| | |-- index.tsx # 子页面路由
| | |-- Layout # 子页面样式组件
| | | |-- ...
| | |-- ...
| |-- ...
|-- i18n # 国际化配置
| |-- index.ts # 国际化实例
| |-- translation # 翻译配置
| |-- index.ts # 默认翻译集
| |-- template.ts # 翻译模板库
| |-- zh-cn.ts # 基于模板的翻译
| |-- en-us.ts # 基于模板的翻译
|-- middleware # 中间件库
| |-- Api # Api 实例
| | | -- ...
| |-- Route # 路由中间件(更好地区分用户是否登录)
| |-- index.ts # 默认导出
| |-- AuthRoute.tsx # 只有登录的用户才能访问(例如后台页面)
| |-- CommonRoute.tsx # 所有用户均可访问(例如主页)
| |-- NoAuthRoute.tsx # 只能由未登录的用户访问(例如登录页面和注册页面)
|-- model # 数据模型
| |-- base # 基础数据(例如 UserData)
| | |-- userData.ts
| | |-- ...
| |-- request # 发送 Api 请求时需要的数据
| | |-- index.ts # 全局请求数据模型
| | |-- imageDeletePayload.ts # 一种请求数据模型,以“Payload”结尾
| | |-- imageUploadPayload.ts
| | |-- loginPayload.ts
| | |-- ...
| | |-- admin # 管理页面的 Api 请求
| | | |-- overviewDataPayload.ts
| | | |-- ...
| |-- response # Api 请求返回的数据
| |-- index.ts # 全局响应数据模型
| |-- batchImagesResponse.ts # 返回的数据通常以基础数据为基础,以“Response”结尾
| |-- loginResponse.ts
| |-- uploadResponse.ts
| |-- ...
| |-- admin # 管理页面的 API 响应
| | |-- overviewDataResponse.ts
| | |-- ...
|-- redux # 全局状态管理器,有效解耦
| |-- hooks.ts # 自定义 Hook
| |-- store.ts # Redux store
| |-- reducers # Redux reducers
| |-- uploader.ts
| |-- viewUpdate.ts
| |-- ...
|-- services # 基于 redux 的 service
| |-- api.ts # 基于 api 中间件和 redux-toolkit 的 Api 实例
|-- utils # 工具库
|-- md5.ts
|-- ...
Prettier
使用 Prettier 管理项目代码风格。
Install
yarn add --dev prettier # 添加为开发依赖
.prettierrc 配置样例
{
"tabWidth": 4,
"printWidth": 100
}
绝对路径
在 tsconfig.json 中配置以使用绝对路径。
{
"compilerOptions": {
"baseUrl": "./src/",
"paths": {
"~/*": ["*"]
}
}
}
命名
所有前端变量、函数、类的命名遵循以下原则:
- 对所有变量使用小驼峰命名法。
- 所有文件名使用小驼峰命名法。
- 函数使用小驼峰命名法,例如
getUser()。 - 未导出的接口使用小驼峰命名法。
- 导出的接口使用大驼峰命名法。
- 组件使用大驼峰命名法,如
<Component/>。 - 所有
class都使用大驼峰命名法。
此外,变量、函数、类和接口的名称必须与其定义和用途相关联。
例如:
- 表示站点配置的变量,我们使用
siteConfig。 - 表示用户名的变量,我们使用
username。 - 表示获取站点配置的函数,我们使用
getSiteConfig。 - 表示站点配置返回值类型的接口,我们使用
SiteConfigResponse。 - 表示查询用户界面请求值的接口,我们使用
UserGetPayload。 - 表示上传图片所需参数的接口,我们使用
ImageUploadPayload。 - 表示表示组件参数类型的接口,我们使用
ComponentProps。
我们也有一些硬性要求:
- 花括号的开头必须紧跟在左侧,不得换行。
- 任何情况下都禁止在代码中使用
var和function关键字。 - 代码必须经过 Prettier 格式化,个人不得擅自修改 Prettier 配置文件。
- 代码必须通过项目配置的 ESLint 检查,任何人未经许可不得更改 ESLint 配置。
Components
存储 Redux JSX 组件。
- 我们希望一个文件中只有一个主要组件,拆分的小部件放在不同的文件中。
- 每个组件都使用一个单独的子文件夹,默认引入位于
index.tsx。 - 组件的子目录名使用小驼峰命名法。
- 我们鼓励使用函数组件。
- 单行代码宽度不得超过 120 字节。
// /src/components/exampleComponent/index.tsx
// 虽然这不是运行所必需的,但我们要求我们从 import React 开始
import React from "react"; // 必须以分号结尾
import SubComponent from "./subComponent"; // 同一组件内的子组件使用相对路径
import { useAppDispatch } from "~/redux/hooks"; // 组件外部的函数使用绝对路径导入
// 组件参数单独定义Props接口,必须导出
// 命名为 组件名称+Props ,使用大驼峰命名法
export interface ExampleComponentProps {
text: string; // 必须以分号结尾
}
// 对于仅在组件内部使用的方法,使用小驼峰命名法
const getHelloWorld = () => {
return "Hello world."
}
// 组件必须使用箭头函数,带有类型声明,使用大驼峰命名法
const ExampleComponent:React.FC<ComponentProps> = (props) => {
const dispatch = useAppDispatch();
// 空行是必要的
// 将相同用途的变量放在一个段落中,在不同段落之间使用空行分割
const helloWorldText = getHelloWorld();
return (
<div>
<p>Hello world.</p>
<span>{helloWorldText}</span> {/* 不要在 JSX 中使用函数 */}
<p>{props.text}</p>
<SubComponent /> {/* 没有子属性的组件使用封闭 XML 区块 */}
</div>
)
}
export default ExampleComponent; // 默认导出主要组件,必须以分号结尾
命名
- 文件名使用小驼峰命名法
- 组件 props 接口使用大驼峰命名法
- 组件使用大驼峰命名法
代码缩进
使用 4 个空格缩进,您可以使用 Prettier 更轻松地管理代码格式。
复杂度控制
我们尽量避免一个组件过于复杂,所以我们可以尽可能将它拆分成更小的组件。
{
"tabWidth": 4
}
Interface
我们需要遵循以下规则:
- 默认导出的接口必须位于 model 文件夹中,并且是一个独立的文件
- 所有解耦后的接口都必须导出
主界面文件放在 src/model 目录的子目录下,并以 .ts 后缀命名。 接口定义以外的语句不得出现在文件中。
// src/model/response/index.ts
// 使用默认值为 any 的泛型封装统一数据类型
export default interface Response<T = any> {
code: number;
msg: string;
data?: T;
error?: string;
}
// src/model/base/user.ts
// Base 接口必须是最完整的
export default interface User {
name: string;
password: string;
age: number;
birthday: Date;
}
// src/model/response/userResponse.ts
import User from "~/model/base/user";
// 没有 Response 嵌套
type UserResponse = Omit<User, "password">
export default UserResponse;
实际应用:
// ...
import Response from "~/model/response";
import UserResponse from "~/model/response/userResponse";
// ...
const apiResult:Response<UserResponse> = useApiResult();
// ...
