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 集成规范

类型定义

• 使用 interfacetype 明确定义 propsstate

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(组件内状态)。

跨组件共享 :采用 ZustandContext 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>  
  );  
};  
相关推荐
小李子呢02111 小时前
前端八股Vue---Vue-router路由管理器
前端·javascript·vue.js
洛_尘3 小时前
Python 5:使用库
java·前端·python
Bigger3 小时前
Bun 能上生产吗?我的实战结论
前端·node.js·bun
kyriewen4 小时前
你的前端滤镜慢得像PPT?用Rust+WebAssembly,一秒处理4K图
前端·rust·webassembly
kyriewen114 小时前
你等的Babel编译,够喝三杯咖啡了——用Rust重写的SWC,只需眨个眼
开发语言·前端·javascript·后端·性能优化·rust·前端框架
IT_陈寒4 小时前
SpringBoot自动配置坑了我,原来要这样绕过去
前端·人工智能·后端
东方小月5 小时前
Claude Code 完整上手指南:MCP、Skills、第三方模型配置一次搞定
前端·人工智能·后端
XZ探长5 小时前
基于 Trae Solo 移动办公修复 Vue3 前端服务问题
前端
蝎子莱莱爱打怪5 小时前
Claude Code 省 Token 小妙招:RTK + Caveman 组合拳
前端·人工智能·后端
Momo__6 小时前
Vue 3.6 Vapor Mode:跳过虚拟 DOM,性能极致优化
前端·vue.js