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>  
  );  
};  
相关推荐
nujnewnehc4 小时前
ps, ai, ae插件都可以用html和js开发了
前端·javascript
Jagger_7 小时前
整洁架构三连问:是什么,怎么做,为什么要用
前端
一个处女座的程序猿O(∩_∩)O7 小时前
React 完全入门指南:从基础概念到组件协作
前端·react.js·前端框架
前端摸鱼匠8 小时前
Vue 3 的defineEmits编译器宏:详解<script setup>中defineEmits的使用
前端·javascript·vue.js·前端框架·ecmascript
里欧跑得慢8 小时前
Flutter 测试全攻略:从单元测试到集成测试的完整实践
前端·css·flutter·web
Jagger_8 小时前
前端整洁架构详解
前端
徐小夕8 小时前
我花一天时间Vibe Coding的开源AI工具,一键检测你的电脑能跑哪些AI大模型
前端·javascript·github
英俊潇洒美少年8 小时前
Vue3 企业级封装:useEventListener + 终极版 BaseEcharts 组件
前端·javascript·vue.js
嵌入式×边缘AI:打怪升级日志9 小时前
使用JsonRPC实现前后台
前端·后端
小码哥_常9 小时前
深度剖析:为什么Android选择了Binder
前端