跳到主要内容

⚛️ 前端开发

“最佳的用户界面是隐形的 —— 它们只是自然而然地工作。”

本章节旨在指导您使用 React 和 Next.js 构建现代、响应式且高性能的 Web 应用程序。


⚛️ React 基础

组件模式 (Component Patterns)

// 函数式组件 (推荐)
export function UserCard({ user, onSelect }) {
const [isHovered, setIsHovered] = useState(false);

return (
<div
className="user-card"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
onClick={() => onSelect(user.id)}
>
<Avatar src={user.avatar} />
<h3>{user.name}</h3>
{isHovered && <UserDetails user={user} />}
</div>
);
}

常用 Hooks

Hook用途示例用例
useState局部状态表单输入、开关
useEffect副作用API 调用、订阅
useContext消费上下文主题、认证状态
useReducer复杂状态逻辑拥有多个字段的表单
useMemo记忆计算值昂贵的计算
useCallback记忆函数传递给子组件的事件处理函数
useRef可变引用DOM 访问、记录前一个值

自定义 Hooks

// useDebounce - 延迟值更新
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);

return () => clearTimeout(timer);
}, [value, delay]);

return debouncedValue;
}

// 用法示例
function SearchInput() {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);

useEffect(() => {
if (debouncedQuery) {
searchAPI(debouncedQuery);
}
}, [debouncedQuery]);

return <input value={query} onChange={e => setQuery(e.target.value)} />;
}

🔲 Next.js

App Router (Next.js 14+)

app/
├── layout.tsx # 根布局
├── page.tsx # 首页 (/)
├── loading.tsx # 加载 UI
├── error.tsx # 错误 UI
├── blog/
│ ├── page.tsx # /blog 页面
│ └── [slug]/
│ └── page.tsx # /blog/:slug 动态路由
└── api/
└── users/
└── route.ts # API 路由

Server Components vs Client Components

// Server Component (默认) - 在服务器端运行
// 无 "use client" 指令
export default async function UserPage({ params }) {
// 可以直接使用 async/await 获取数据
const user = await fetchUser(params.id);

return <UserProfile user={user} />;
}

// Client Component - 在浏览器端运行
"use client";

import { useState } from 'react';

export function Counter() {
const [count, setCount] = useState(0);

return (
<button onClick={() => setCount(count + 1)}>
计数: {count}
</button>
);
}

数据获取模式 (Data Fetching)

// Server Component - 直接获取数据
async function BlogPosts() {
const posts = await fetch('https://api.example.com/posts', {
cache: 'no-store', // 或 'force-cache', revalidate: 3600
}).then(res => res.json());

return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}

// Client Component - 使用 SWR 或 React Query
"use client";
import useSWR from 'swr';

function UserProfile({ userId }) {
const { data, error, isLoading } = useSWR(
`/api/users/${userId}`,
fetcher
);

if (error) return <div>加载失败</div>;
if (isLoading) return <div>加载中...</div>;

return <div>{data.name}</div>;
}

API 路由 (API Routes)

// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
const users = await prisma.user.findMany();
return NextResponse.json(users);
}

export async function POST(request: NextRequest) {
const body = await request.json();
const user = await prisma.user.create({ data: body });
return NextResponse.json(user, { status: 201 });
}

🎨 Tailwind CSS

Utility-First 方法论

// 传统 CSS
<div className="card">...</div>
// .card { padding: 1rem; border-radius: 0.5rem; ... }

// Tailwind CSS
<div className="p-4 rounded-lg bg-white shadow-md hover:shadow-lg transition-shadow">
...
</div>

常用模式

// 响应式设计
<div className="w-full md:w-1/2 lg:w-1/3">
{/* 移动端全宽,平板半宽,桌面端三分之一宽 */}
</div>

// 暗模式
<div className="bg-white dark:bg-gray-800 text-black dark:text-white">
{/* 自动适应系统偏好或主题切换 */}
</div>

// 悬停与焦点状态
<button className="bg-blue-500 hover:bg-blue-600 focus:ring-2 focus:ring-blue-300">
点击我
</button>

// Flexbox 居中
<div className="flex items-center justify-center h-screen">
<Content />
</div>

使用 clsx 进行组件组合

import { clsx } from 'clsx';

function Button({ variant = 'primary', size = 'md', className, children }) {
return (
<button
className={clsx(
'rounded font-medium transition-colors',
{
'bg-blue-500 text-white hover:bg-blue-600': variant === 'primary',
'bg-gray-200 text-gray-800 hover:bg-gray-300': variant === 'secondary',
'px-2 py-1 text-sm': size === 'sm',
'px-4 py-2': size === 'md',
'px-6 py-3 text-lg': size === 'lg',
},
className
)}
>
{children}
</button>
);
}

🔄 状态管理

方案复杂度最适合
useState组件局部状态
useContext简单全局状态(主题、认证)
useReducer复杂组件内部状态
Zustand轻量级全局状态
Jotai原子化状态模型
Redux Toolkit大型企业应用

Zustand 示例

import { create } from 'zustand';

const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));

function Counter() {
const { count, increment, decrement } = useStore();

return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}

📝 详细主题


前端最佳实践
  1. 组件组合 - 优先使用小型、可复用的组件。
  2. 状态提升 - 在正确的层级共享状态。
  3. 合理记忆化 - 避免过度优化,按需使用 useMemo/useCallback
  4. 可访问性 - 使用语义化的 HTML 和 ARIA 属性。
  5. 渐进增强 - 确保在禁用 JavaScript 时也能基本可用。