React 核心技术深度笔记
一、非交互性更新的优先级
1.1 理解更新优先级
React 18 引入了优先级调度系统,不同类型的更新有不同的优先级:
| 优先级 | 类型 | 说明 |
|---|---|---|
| Immediate | 同步更新 | 需要立即执行,不能中断 |
| UserBlocking | 用户交互 | 点击、输入等,需要快速响应 |
| Normal | 普通更新 | 数据获取后的更新 |
| Low | 低优先级 | 非关键更新,如日志上报 |
| Idle | 空闲时执行 | 可延迟到浏览器空闲时 |
1.2 非交互性更新的处理
场景示例:
import { startTransition, useEffect } from 'react';
function SearchResults({ query }) {
const [results, setResults] = useState([]);
useEffect(() => {
// 低优先级更新:不会阻塞用户交互
startTransition(() => {
fetchResults(query).then(data => {
setResults(data);
});
});
}, [query]);
return <ResultsList items={results} />;
}
使用 useTransition 钩子:
import { useTransition } from 'react';
function App() {
const [isPending, startTransition] = useTransition();
const handleSearch = (query) => {
// 标记为过渡更新
startTransition(() => {
setSearchQuery(query);
});
};
return (
<>
<SearchInput onChange={handleSearch} />
{isPending && <LoadingIndicator />}
<Results query={searchQuery} />
</>
);
}
二、Server Components(RSC)深度解析
2.1 什么是 Server Components
定义:在服务端运行的 React 组件,无需发送到客户端
核心优势:
- 📦 减少 JS 体积:不包含在客户端 bundle 中
- 🚀 数据获取更高效:直接在服务端访问数据库
- 🎯 SEO 友好:服务端渲染完整 HTML
2.2 RSC vs SSR vs Client Components
| 特性 | Server Components | SSR | Client Components |
|---|---|---|---|
| 运行位置 | 服务端 | 服务端渲染,客户端交互 | 客户端 |
| 可访问 | 数据库、文件系统 | 仅通过 API | 浏览器 API |
| JS 体积 | 0KB | 需要 hydration | 包含在 bundle |
| 交互能力 | 无 | 需要 hydration | 完全支持 |
2.3 RSC 实践
创建 Server Component:
// app/PostList.server.jsx
async function PostList() {
// 直接在服务端获取数据
const posts = await db.posts.findMany({
orderBy: { createdAt: 'desc' },
take: 10
});
return (
<ul>
{posts.map(post => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.excerpt}</p>
</li>
))}
</ul>
);
}
混合使用 Server/Client Components:
// app/Blog.jsx
import PostList from './PostList.server';
import CommentSection from './CommentSection.client';
function Blog({ postId }) {
return (
<div>
{/* Server Component:渲染内容 */}
<PostList />
{/* Client Component:处理交互 */}
<CommentSection postId={postId} />
</div>
);
}
2.4 RSC 数据流模式
┌─────────────────────────────────────────────────────────────┐
│ Server Side │
├─────────────────────────────────────────────────────────────┤
│ Server Components │
│ ├─ 获取数据(DB/API) │
│ ├─ 渲染为特殊格式(React Server Component Payload) │
│ └─ 发送到客户端 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Client Side │
├─────────────────────────────────────────────────────────────┤
│ Client Components │
│ ├─ 接收 Server Component 的渲染结果 │
│ ├─ 进行 hydration(如果需要) │
│ └─ 处理用户交互 │
└─────────────────────────────────────────────────────────────┘
2.5 RSC 适用场景
✅ 内容展示组件:博客文章、产品列表、静态页面
✅ 数据密集型组件:仪表盘、报表
✅ SEO 关键页面:首页、落地页
❌ 高交互组件:表单、实时编辑器
❌ 需要浏览器 API:DOM 操作、事件监听
三、React.memo 完全指南
3.1 什么是 React.memo
定义:高阶组件(HOC),用于对组件输出进行浅比较,避免不必要的重渲染
工作原理:
// 伪代码展示 React.memo 的工作方式
function memo(Component) {
return function MemoizedComponent(props) {
// 比较前后 props
if (propsChanged(prevProps, currentProps)) {
return <Component {...props} />;
}
// 返回缓存的结果
return cachedResult;
};
}
3.2 使用场景
场景一:纯展示组件
const UserCard = React.memo(function UserCard({ user }) {
return (
<div className="card">
<img src={user.avatar} alt={user.name} />
<h3>{user.name}</h3>
<p>{user.bio}</p>
</div>
);
});
场景二:列表项组件
const TodoItem = React.memo(function TodoItem({ todo, onToggle }) {
return (
<div onClick={() => onToggle(todo.id)}>
<input
type="checkbox"
checked={todo.completed}
readOnly
/>
<span className={todo.completed ? 'completed' : ''}>
{todo.text}
</span>
</div>
);
});
3.3 自定义比较函数
深度比较场景:
const DeepMemoComponent = React.memo(
MyComponent,
(prevProps, nextProps) => {
// 自定义比较逻辑
return (
prevProps.id === nextProps.id &&
prevProps.data.value === nextProps.data.value
);
}
);
3.4 React.memo 的性能考量
什么时候使用:
- 组件渲染成本高(复杂计算、大量子组件)
- 组件频繁接收相同 props
- 在大型列表中使用
什么时候不使用:
- 简单组件(比较成本 > 渲染成本)
- props 频繁变化
- 组件内部有 useState/useContext
3.5 React.memo vs useMemo
| 特性 | React.memo | useMemo |
|---|---|---|
| 作用范围 | 组件级 | 值/计算结果 |
| 比较方式 | 浅比较 props | 比较依赖数组 |
| 返回值 | 新组件 | 缓存的值 |
| 使用方式 | 包装组件 | 包装计算表达式 |
// React.memo - 缓存组件渲染
const MemoizedList = React.memo(List);
// useMemo - 缓存计算结果
const expensiveValue = useMemo(() => {
return computeExpensiveData(data);
}, [data]);
四、组件设计原则
4.1 单一职责原则
定义:一个组件应该只负责一件事情
反例:
// ❌ 违反单一职责:同时处理数据获取和UI渲染
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]);
if (!user) return <Loading />;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
{/* ... 更多UI */}
</div>
);
}
正例:
// ✅ 数据获取逻辑
function useUser(userId) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]);
return user;
}
// ✅ 纯UI组件
function UserProfile({ user }) {
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
// ✅ 使用
function ProfilePage({ userId }) {
const user = useUser(userId);
if (!user) return <Loading />;
return <UserProfile user={user} />;
}
4.2 可复用性原则
设计通用、可配置的组件
示例:通用 Button 组件
const Button = ({
children,
variant = 'primary',
size = 'md',
disabled = false,
onClick,
className = '',
...props
}) => {
const baseStyles = 'px-4 py-2 rounded font-medium transition-all';
const variants = {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
danger: 'bg-red-500 text-white hover:bg-red-600',
};
const sizes = {
sm: 'text-sm px-3 py-1',
md: 'text-base',
lg: 'text-lg px-6 py-3',
};
return (
<button
disabled={disabled}
onClick={onClick}
className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}
{...props}
>
{children}
</button>
);
};
// 使用
<Button>默认按钮</Button>
<Button variant="secondary" size="sm">次要按钮</Button>
<Button variant="danger" disabled>危险按钮</Button>
4.3 纯组件原则
定义:相同输入产生相同输出,无副作用
纯组件特征:
- 不修改传入的 props
- 不依赖外部状态
- 不产生副作用(如 API 调用、DOM 操作)
- 相同输入始终返回相同输出
示例:
// ✅ 纯组件
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// ❌ 不纯组件
function BadGreeting({ name }) {
// 副作用:直接修改 props
name = name.toUpperCase();
return <h1>Hello, {name}!</h1>;
}
五、React.lazy() 与代码分割
5.1 什么是代码分割
定义:将应用代码分割成多个小块,按需加载
核心价值:
- 📦 减少初始加载体积
- ⚡ 提升首屏加载速度
- 🚀 优化用户体验
5.2 React.lazy() 基础用法
import { lazy, Suspense } from 'react';
// 动态导入组件
const HeavyChart = lazy(() => import('./HeavyChart'));
const DataTable = lazy(() => import('./DataTable'));
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Loading />}>
<HeavyChart />
<DataTable />
</Suspense>
</div>
);
}
5.3 路由级代码分割
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
const Dashboard = lazy(() => import('./Dashboard'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<LoadingScreen />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
5.4 高级用法:命名导出
// 导出多个组件
export const Chart = () => <div>Chart</div>;
export const Table = () => <div>Table</div>;
// 导入指定组件
const { Chart } = await import('./components');
// 使用命名导出的 lazy 加载
const Chart = lazy(() =>
import('./components').then(module => ({ default: module.Chart }))
);
5.5 React.lazy vs loadable-components
| 特性 | React.lazy | loadable-components |
|---|---|---|
| SSR 支持 | ❌ | ✅ |
| 加载状态 | 需要 Suspense | 内置 loading 状态 |
| 错误处理 | 需要 Error Boundary | 内置 error 状态 |
| 预加载 | ❌ | ✅ |
六、学习阶段指南
6.1 进阶阶段:核心技能
Hooks 精通:
- useState/useEffect/useContext/useReducer
- useCallback/useMemo/useRef
- 自定义 Hooks 设计模式
状态管理:
- Context API 深度应用
- Redux Toolkit 或 Zustand
- 状态规范化与选择器
路由:
- React Router 6.x 完整掌握
- 嵌套路由、路由守卫
- 动态路由与参数处理
项目结构:
src/
├── components/ # 通用组件
│ ├── layout/ # 布局组件
│ └── ui/ # UI 原子组件
├── features/ # 功能模块
│ └── auth/ # 认证模块
│ ├── hooks/ # 自定义 hooks
│ ├── components/ # 模块组件
│ └── index.js # 模块入口
├── hooks/ # 全局 hooks
├── utils/ # 工具函数
└── App.js
6.2 高级阶段:性能优化
渲染优化:
- React.memo、useMemo、useCallback
- 虚拟列表(react-window/react-virtualized)
- 状态提升与拆分
资源优化:
- 图片优化(WebP/AVIF)
- 代码分割与懒加载
- 资源预加载(preload/prefetch)
服务端渲染:
- Next.js App Router
- Server Components
- 数据获取策略(getServerSideProps、fetch)
性能监控:
- Web Vitals
- React DevTools Profiler
- 自定义性能指标
6.3 工程化阶段:企业级实践
TypeScript:
- 类型安全、泛型、类型体操
- 类型定义文件(.d.ts)
- ESLint + TypeScript 集成
测试体系:
- 单元测试(Jest + RTL)
- 集成测试(Playwright)
- 端到端测试
构建工具:
- Vite 配置与插件
- Webpack 高级配置
- 构建优化策略
CI/CD:
- GitHub Actions/GitLab CI
- 自动化测试与部署
- 环境配置与变量管理
七、最佳实践总结
7.1 性能优化优先级
- 架构层面:使用 Server Components 减少客户端 JS
- 组件层面:React.memo + useMemo/useCallback 优化渲染
- 打包层面:React.lazy + Suspense 实现按需加载
- 运行时层面:虚拟滚动、代码分割、资源优化
7.2 组件设计检查清单
- 是否符合单一职责?
- 是否可复用、可配置?
- 是否为纯组件(无副作用)?
- props 是否最小化、清晰?
- 是否有合适的错误处理?
7.3 RSC 使用决策树
需要渲染内容吗?
│
├─ 是 → 需要交互吗?
│ │
│ ├─ 是 → Client Component
│ └─ 否 → Server Component
│
└─ 否 → 考虑是否需要该组件
这些笔记涵盖了你提到的所有主题,从基础概念到高级实践都有详细说明。建议根据自己的学习阶段,从进阶阶段开始逐步深入,重点关注 Server Components 和性能优化,这是当前 React 生态的核心竞争力所在。