FE-09-React 高级:Hooks 原理、并发渲染、Server Components
本节目标:理解 React Hooks 的底层原理(链表、闭包)、Concurrent Mode、Server Components,掌握 React 19 新特性。
1. React 思维模型
核心思想:
- 声明式 UI:描述”是什么”而不是”怎么改”
- 组件化:UI = 组件树
- 单向数据流:props down, events up
- 虚拟 DOM:JS 对象描述 UI,diff 后最小化更新真实 DOM
1 | function App() { |
2. Hooks 规则与原理
2.1 Hooks 的两条铁律
- 只在最顶层调用(不要在循环/条件/嵌套函数里)
- 只在 React 函数里调用(组件函数或其他 Hook)
2.2 为什么?
React 内部用链表存储每个组件的 Hooks:
1 | // 简化源码 |
如果在条件里调用 Hook:
1 | function Counter({ cond }) { |
所以 ESLint 插件 eslint-plugin-react-hooks 会强制要求 Hooks 顺序稳定。
3. 核心 Hooks 深入
3.1 useState
1 | const [count, setCount] = useState(0); |
3.2 useEffect
1 | useEffect(() => { |
执行时机:
- 组件挂载后
- 依赖项变化后,先清理再执行
- 组件卸载前清理
3.3 useLayoutEffect
同步版本,在 DOM 更新后、浏览器绘制前执行:
1 | useLayoutEffect(() => { |
对比:
useEffect:异步,浏览器已绘制useLayoutEffect:同步,浏览器未绘制- 99% 用 useEffect,DOM 测量/同步修改用 useLayoutEffect
3.4 useMemo / useCallback
1 | // useMemo:缓存计算结果 |
经验法则:先不优化,profile 后再决定。
3.5 useRef
1 | const ref = useRef(null); |
3.6 useReducer
1 | const initial = { count: 0 }; |
何时用 useReducer:
- 状态逻辑复杂(多个子值相互依赖)
- 下一状态取决于前状态
- 想集中管理 action 类型
3.7 useContext
1 | const ThemeContext = createContext('light'); |
注意:context 变化会导致所有消费者 re-render,大型应用慎用。
3.8 自定义 Hook
1 | // useLocalStorage.ts |
4. 性能优化
4.1 React.memo
浅比较 props,没变就不重渲染:
1 | const Button = React.memo(function Button({ onClick, children }) { |
配合 useCallback / useMemo:
1 | function Parent() { |
4.2 列表 key
1 | // ✓ 稳定的、唯一的 key |
4.3 状态提升 vs 下放
1 | // ✓ 状态尽量下放 |
4.4 虚拟列表(长列表)
1 | npm install react-window |
1 | import { FixedSizeList } from 'react-window'; |
5. Concurrent 模式(React 18+)
核心能力:可中断的渲染。
5.1 自动批处理
1 | // React 18 之前:只在事件处理器中批处理 |
5.2 useTransition
标记非紧急更新,可被紧急更新打断:
1 | import { useTransition } from 'react'; |
5.3 useDeferredValue
延迟某个值的更新:
1 | import { useDeferredValue } from 'react'; |
5.4 Suspense
等待异步组件,渲染 fallback:
1 | import { Suspense, lazy } from 'react'; |
数据获取(搭配 React Query / SWR):
1 | <Suspense fallback={<Skeleton />}> |
6. Server Components(RSC)
React 的新范式:组件在服务器渲染,不发到客户端。
6.1 优势
- bundle size 减小:服务器组件的代码不发到浏览器
- 直接访问后端:DB、文件系统、内部服务
- 首屏更快:HTML 流式响应
- SEO 友好
6.2 用法(Next.js 13+ App Router)
1 | // app/page.tsx(默认 Server Component) |
6.3 何时用 Server vs Client
| 用 Server | 用 Client |
|---|---|
| 静态内容、SEO | 用户交互(onClick, onChange) |
| 数据获取、DB 查询 | 浏览器 API(localStorage, fetch 的浏览器版本) |
| 大型依赖(marked, sharp) | 状态管理(useState, useReducer) |
| 敏感逻辑(API keys) | 动画、过渡效果 |
7. React 19 新特性
1 | // 1. use() Hook:读取 Promise/Context |
8. 状态管理选型
| 方案 | 适用场景 | 缺点 |
|---|---|---|
| useState + Context | 小应用、跨组件共享 | 频繁更新性能差 |
| Redux Toolkit | 大型应用、复杂状态 | 学习曲线 |
| Zustand | 中小型应用、轻量级 | 生态较小 |
| Jotai | 原子化状态 | 生态较小 |
| Recoil | Meta 风格(已不推荐) | 维护减少 |
| TanStack Query | 服务端状态 | 不是 UI 状态 |
Zustand 示例:
1 | import { create } from 'zustand'; |
9. 测试
React Testing Library(推荐):
1 | import { render, screen, fireEvent } from '@testing-library/react'; |
Vitest(更快的 Jest 替代):
1 | import { describe, it, expect } from 'vitest'; |
小结
| 概念 | 关键点 |
|---|---|
| Hooks | 链表存储,必须顶层调用 |
| 渲染 | 函数式组件返回 JSX |
| 状态 | useState/useReducer,state 不可变 |
| 副作用 | useEffect(异步)vs useLayoutEffect(同步) |
| 性能 | memo、useCallback、useMemo、下放状态 |
| 并发 | useTransition、useDeferredValue、Suspense |
| RSC | 默认在服务器,要交互加 ‘use client’ |
| React 19 | use()、Form Actions、useOptimistic |
2026 React 生态推荐:
- 新项目:Next.js 14+ App Router(默认 RSC)
- 库:Vite + React 19
- 状态:Zustand(小)/ Redux Toolkit(大)
- 数据:TanStack Query (React Query)
- 样式:Tailwind CSS / CSS Modules
- 测试:Vitest + React Testing Library + Playwright
下一节讲 Vue 3 进阶:响应式原理、Composition API、性能优化。
- 本文作者: CoderSong
- 本文链接: https://jack-song-gif.github.io/2026/09/23/FE-09-React高级:Hooks与并发渲染/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!