Next.js 组件开发最佳实践文档(TypeScript 版)

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>  
  );  
};  
相关推荐
JavaGuide9 小时前
NVIDIA 又开源了!这次给 AI Agent 加上权限管控
前端·后端
excel9 小时前
prisma 如何处理数据库竞态
前端·数据库·后端
莪_幻尘10 小时前
Skill 体检:30 个 Skill 全凭感觉?体检器先自曝了 8 个“假 0 分
前端·人工智能·llm
风骏时光牛马10 小时前
AI模型综合能力评测:性能、指令遵循与多场景实测对比
前端
Frag0ut10 小时前
Chrome与Chromium内核浏览器在Windows 11上的新特性全景解析
前端·chrome·windows·web安全·chromium·gemini ai·playready drm
hiahiahia12311 小时前
实现完整 Tool Dispatcher
开发语言·前端
IT_陈寒11 小时前
Java线程池这破玩意,差点让我周末加班排查到凌晨
前端·人工智能·后端
Mr_Mao12 小时前
告别选型困难!集 VueUse、ahooks、Mantine 于一身:286 个 Hook 的 ReaUse 来了
前端·javascript·react.js
泡海椒12 小时前
趋势分析报表:jquick-pdf折线图PDF生成实战
java·大数据·运维·服务器·前端·pdf
默_笙13 小时前
🚙 一条腿走路会摔:ES 关键词检索、混合召回与 ReRank 裁判
前端·javascript