1. 项目结构与组件规范
文件组织
bash
/src
├── components
│ ├── ui # 基础 UI 组件(无状态)
│ │ └── Button.tsx
│ └── features # 业务组件(含状态与逻辑)
│ └── UserList
│ ├── UserList.tsx # 主组件
│ ├── useUserList.ts # 自定义 Hook(状态与逻辑)
│ └── types.ts # 类型定义
原则 :
• 基础 UI 组件 :保持无状态,仅接收 props
,如按钮、输入框等。
• 业务组件:分离为 UI 层、状态层、逻辑层,通过自定义 Hook 管理副作用(如 API 调用)。
2. 组件设计原则
单一职责
• 每个组件仅解决一个核心问题(如展示、表单提交、数据加载)。
• 反例:一个组件同时处理数据请求、渲染和状态修改。
可复用性
• 通过 props
传递配置,避免硬编码逻辑。例如:
tsx
type ButtonProps = {
variant?: "primary" | "secondary";
onClick: () => void;
};
3. TypeScript 集成规范
类型定义
• 使用 interface
或 type
明确定义 props
和 state
:
typescript
// types.ts
export interface User {
id: string;
name: string;
email: string;
}
export type UserListProps = {
initialUsers: User[];
};
组件类型注解
tsx
import { FC } from "react";
const UserList: FC<UserListProps> = ({ initialUsers }) => {
// ...
};
配置校验
• 使用 zod
验证 API 响应格式:
typescript
import { z } from "zod";
const UserSchema = z.object({
id: z.string(),
name: z.string().min(2),
});
4. UI 与状态分离实现
状态管理方案
• 轻量级场景 :使用 useState
/useReducer
(组件内状态)。
• 跨组件共享 :采用 Zustand
或 Context API
(全局状态)。
状态与 UI 分离示例
typescript
// useUserList.ts
import { useState } from "react";
export const useUserList = (initialUsers: User[]) => {
const [users, setUsers] = useState<User[]>(initialUsers);
const addUser = (user: User) => {
setUsers([...users, user]);
};
return { users, addUser };
};
5. 操作逻辑解耦
副作用处理
• 将 API 调用、事件处理等逻辑封装为独立函数或服务层:
typescript
// api/user.ts
export const fetchUsers = async (): Promise<User[]> => {
const response = await fetch("/api/users");
return UserSchema.array().parse(response.data);
};
自定义 Hook 整合
typescript
// useUserList.ts
import { useEffect } from "react";
export const useUserList = () => {
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
const loadData = async () => {
const data = await fetchUsers();
setUsers(data);
};
loadData();
}, []);
return { users };
};
6. 示例组件演示
用户列表组件(完整实现)
tsx
// UserList.tsx
import { FC } from "react";
import { useUserList } from "./useUserList";
import { User, UserListProps } from "./types";
import Button from "@/components/ui/Button";
const UserList: FC<UserListProps> = ({ initialUsers }) => {
const { users, addUser } = useUserList(initialUsers);
return (
<div>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
<Button
variant="primary"
onClick={() => addUser({ id: "1", name: "New User" })}
>
添加用户
</Button>
</div>
);
};