01

React 是什么?

理解 React 的设计哲学、核心定位和为什么它改变了前端开发的格局

React 的诞生与定位

2013 年,Facebook(现 Meta)在 JSConf 上开源了一个名为 React 的 JavaScript 库。它的核心理念非常简单:UI = f(state)——将用户界面视为状态的函数映射。

这个看似简单的理念,彻底改变了前端开发的范式。在 React 之前,开发者需要手动操作 DOM 来更新界面(命令式编程);React 之后,开发者只需描述界面应该呈现什么样子,React 负责高效地更新 DOM(声明式编程)。

💡
为什么选择 React?

React 并不是第一个前端框架,但它引入了三个革命性的概念:组件化(将 UI 拆分为独立、可复用的组件)、虚拟 DOM(通过 diff 算法最小化 DOM 操作)、单向数据流(数据从父组件流向子组件,可预测、可调试)。这三个概念至今仍是现代前端框架的设计基础。

📦

声明式编程

你只需描述「UI 应该长什么样」,React 负责高效更新 DOM。当数据变化时,React 自动重新渲染组件,你不需要手动操作 DOM 节点。

🧩

组件化架构

将复杂的 UI 拆分为独立、可复用的组件。每个组件管理自己的状态和渲染逻辑。组件可以嵌套组合,像乐高积木一样构建完整的界面。

虚拟 DOM

React 在内存中维护一个虚拟 DOM 树。状态变化时,React 先在虚拟 DOM 上计算差异(diff),然后只更新真实 DOM 中变化的部分,避免昂贵的全量 DOM 操作。

🌐

生态丰富

React 拥有全球最大的前端生态系统:Next.js(全栈框架)、React Native(移动开发)、Redux/Zustand(状态管理)、React Router(路由)。一次学习,全栈受益。

第一个 React 组件

让我们从一个简单的 HelloMessage 组件开始,理解 React 组件的基本结构。

JSX
// 最简单的 React 函数组件
function HelloMessage({ name }) {
  return (
    <div className="greeting">
      <h1>Hello, {name}!</h1>
      <p>Welcome to React</p>
    </div>
  );
}

// 使用组件
const root = ReactDOM.createRoot(
  document.getElementById('root')
);
root.render(<HelloMessage name="Alice" />);
解读

React 组件的核心概念:

  • 函数组件:一个返回 JSX 的普通 JavaScript 函数
  • Props({ name }):组件的输入参数,父组件传入的数据
  • JSX:JavaScript 的语法扩展,可以在 JS 中写类 HTML 结构
  • className:React 中用 className 替代 class(class 是 JS 保留字)
  • createRoot:React 18 的新 API,创建渲染根节点

React 渲染流程:从状态到界面

理解 React 的渲染流程,是掌握 React 性能优化的基础。以下是 React 从状态变化到 DOM 更新的完整流程。

🔄
状态变化
触发渲染
🧩
虚拟DOM计算
🔎
Diff算法
🔧
最小更新
💻
真实DOM

课程路线图

📁 课程路线图
📚 模块 1:React 是什么(当前位置)
设计哲学、第一个组件、渲染流程
🧠 模块 2:核心概念
组件、Props、State、Hooks、生命周期
🛠 模块 3:实践应用
状态管理、表单处理、API 集成、路由
🚀 模块 4:进阶主题
Context、性能优化、自定义 Hook、Server Components
✅ 模块 5:总结与练习
最佳实践、综合练习、React 生态

React 的核心理念 "UI = f(state)" 是什么意思?

02

React 的核心概念

深入理解组件、Props、State、Hooks 和生命周期——React 开发的五大基石

组件与 Props

组件是 React 的基本构建单元。它是一个返回 UI 元素的 JavaScript 函数(或类)。Props 是父组件传递给子组件的数据,实现组件间的通信。

🧩
组件设计原则

好的组件遵循单一职责原则——每个组件只做一件事。如果组件变得复杂,就应该拆分为更小的子组件。理想情况下,一个组件的代码不超过 100 行。组件名使用 PascalCase(如 UserCard、ShoppingCart),与 HTML 元素区分。

JSX
// 父组件:组合多个子组件
function UserDashboard() {
  const user = { name: "Alice", role: "admin" };

  return (
    <div className="dashboard">
      {/* 数据通过 props 向下流动 */}
      <UserHeader user={user} />
      <UserStats userId={user.id} />
      <UserActivity userId={user.id} />
    </div>
  );
}

// 子组件:接收 props 并渲染
function UserHeader({ user }) {
  return (
    <header>
      <h1>{user.name}</h1>
      <span className="badge">{user.role}</span>
    </header>
  );
}
解读

组件与 Props 的核心模式:

  • 组合模式:父组件包含子组件,形成组件树
  • Props 传递:数据通过 props 从父组件流向子组件
  • 解构赋值:({ user }) 直接从 props 中提取参数
  • 单向数据流:子组件只读取 props,不修改

State 与 Hooks

如果说 Props 是组件的输入,那么 State 就是组件的内部记忆。Hooks 是 React 16.8 引入的 API,让函数组件也能使用状态和副作用等功能。

🔄

useState

最基础的 Hook。声明一个状态变量和更新函数。const [count, setCount] = useState(0)。状态更新触发重新渲染。支持函数式更新:setCount(prev => prev + 1)。

useEffect

处理副作用:API 调用、DOM 操作、事件监听、定时器。第二个参数是依赖数组,控制何时重新执行。空数组 [] 表示只在挂载时执行一次。返回清理函数处理资源释放。

📚

useRef

持有可变引用,不触发重新渲染。常见用途:引用 DOM 元素(focus 管理)、存储上一次的值、存储不需要触发渲染的定时器 ID。

📈

useMemo / useCallback

性能优化 Hook。useMemo 缓存计算结果,useCallback 缓存函数引用。避免不必要的重新计算和子组件重新渲染。但不要过度使用——缓存本身也有开销。

JSX
function Counter() {
  const [count, setCount] = useState(0);
  const [step, setStep] = useState(1);

  // 副作用:每次 count 变化时更新标题
  useEffect(() => {
    document.title = `Count: ${count}`;
    return () => { document.title = "React App"; };
  }, [count]); // 依赖:只在 count 变化时执行

  // 计算属性:缓存计算结果
  const doubled = useMemo(() => count * 2, [count]);

  return (
    <div>
      <p>Count: {count} | Doubled: {doubled}</p>
      <button onClick={() => setCount(c => c + step)}>
        Increment by {step}
      </button>
    </div>
  );
}
解读

Hooks 的使用模式:

  • useState:声明状态,[value, setter] 解构
  • useEffect:副作用处理,[count] 是依赖数组
  • 清理函数:return 的函数在组件卸载或依赖变化前执行
  • useMemo:只有 count 变化时才重新计算 doubled
  • 函数式更新:setCount(c => c + step) 确保基于最新值更新

组件生命周期与 useEffect

理解组件的生命周期——从挂载到更新到卸载——是写出正确 React 代码的关键。在函数组件中,生命周期通过 useEffect 实现。

挂载(Mount)— 组件首次渲染

初始化副作用
🗑
清理函数注册

更新(Update)— 状态或 Props 变化

🔄
响应数据变化
📦
自动批处理

卸载(Unmount)— 组件销毁

🚫
资源释放
点击组件了解生命周期的每个阶段

React 中 Props 和 State 的关键区别是什么?

useEffect 的依赖数组为空 [] 时,副作用何时执行?

03

React 的实践应用

状态管理、表单处理、API 集成和路由——构建真实 React 应用的核心技能

状态管理:从本地到全局

React 应用的状态管理分为三个层次:组件本地状态(useState)、跨组件共享状态(Context)、全局状态管理(Zustand/Redux)。选择合适的层次,是 React 开发的重要决策。

🧠
状态管理的选型原则

不要过度工程化。大多数应用只需要 useState + Context。只有当状态逻辑非常复杂(如购物车、协作编辑、实时仪表盘)时,才需要引入 Zustand 或 Redux。 Zustand 是 2024 年最推荐的轻量级状态管理库。

JSX
// 简单的待办事项应用
function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState("");

  const addTodo = useCallback(() => {
    if (!input.trim()) return;
    setTodos(prev => [...prev, {
      id: Date.now(),
      text: input,
      completed: false
    }]);
    setInput("");
  }, [input]);

  const toggleTodo = useCallback((id) => {
    setTodos(prev => prev.map(todo =>
      todo.id === id
        ? { ...todo, completed: !todo.completed }
        : todo
    ));
  }, []);

  return (
    <div>
      <input value={input}
        onChange={e => setInput(e.target.value)}
        onKeyDown={e => e.key === 'Enter' && addTodo()}
      />
      <TodoList todos={todos} onToggle={toggleTodo} />
    </div>
  );
}
解读

状态管理的核心模式:

  • 不可变更新:[...prev, newItem] 创建新数组,不修改原数组
  • useCallback:缓存函数引用,避免子组件不必要的重新渲染
  • 展开运算符:{ ...todo, completed: !todo.completed } 更新单个属性
  • 受控组件:input 的值由 state 控制,onChange 更新 state

表单处理与数据获取

表单是 Web 应用最常见的交互元素。React 的受控组件模式让表单状态管理变得清晰可预测。

JSX
function UserProfile() {
  const [formData, setFormData] = useState({
    name: "", email: "", bio: ""
  });
  const [status, setStatus] = useState("idle");

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus("submitting");
    try {
      await fetch('/api/profile', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData)
      });
      setStatus("success");
    } catch (err) {
      setStatus("error");
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" value={formData.name}
        onChange={handleChange} />
      <button disabled={status === "submitting"}>
        {status === "submitting" ? "Saving..." : "Save"}
      </button>
    </form>
  );
}
解读

表单处理的关键模式:

  • 统一状态对象:所有表单字段存储在一个对象中
  • 动态属性名:[name]: value 根据字段名动态更新
  • 提交状态管理:idle/submitting/success/error 四种状态
  • 防重复提交:disabled={status === "submitting"}

API 数据获取模式

React 组件获取 API 数据是一个常见但需要正确处理的场景。自定义 Hook 是封装数据获取逻辑的最佳方式。

🔍

自定义 Hook:useFetch

封装 fetch 调用,返回 { data, loading, error }。支持自动重试、缓存和取消请求。将重复的数据获取逻辑抽象为可复用的 Hook。

📦

SWR / React Query

生产级数据获取库。自动缓存、重新验证、乐观更新、分页、无限滚动。SWR 更轻量,React Query 功能更丰富。推荐新项目使用 SWR。

🚫

请求取消

使用 AbortController 在组件卸载时取消未完成的请求。避免"无法对已卸载的组件执行状态更新"的警告和内存泄漏。

在 React 中,为什么状态更新必须使用不可变方式(如展开运算符)?

04

React 的进阶主题

Context API、性能优化、自定义 Hook 和 React Server Components——高级开发者的必备技能

Context API:跨组件数据共享

当多个层级的组件需要共享同一份数据时(如主题、用户信息、语言设置),逐层传递 Props 会变得非常繁琐。Context API 解决了这个问题——让数据跨越组件层级直接传递。

JSX
// 1. 创建 Context
const ThemeContext = createContext('light');
const UserContext = createContext(null);

// 2. 在顶层组件提供数据
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <UserContext.Provider value={{ name: "Alice" }}>
        <Layout />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

// 3. 在任意深层组件中使用
function ThemedButton() {
  const theme = useContext(ThemeContext);
  const user = useContext(UserContext);

  return (
    <button className={`btn btn-${theme}`}>
      {user.name}'s Button
    </button>
  );
}
解读

Context API 的三步使用模式:

  • createContext:创建 Context 对象,参数是默认值
  • Provider:在顶层包裹子组件树,提供共享数据
  • useContext:在任意深层组件中直接访问数据,无需 Props 传递
  • 多 Context:可以嵌套多个 Provider,管理不同的共享数据

React 性能优化

React 默认已经很高效,但在复杂应用中仍然需要针对性的优化。以下是 React 性能优化的核心策略。

📊

React.memo

浅比较 Props,如果没变就跳过重新渲染。适合渲染开销大、Props 不经常变化的组件。const MemoComp = React.memo(ExpensiveComponent)。配合 useCallback 使用效果更好。

📦

useMemo

缓存计算结果,避免每次渲染都重新计算。const sorted = useMemo(() => heavySort(data), [data])。适合排序、过滤等计算密集型操作。只在依赖变化时重新计算。

🔧

虚拟列表

渲染长列表时,只渲染可见区域的项目。使用 react-window 或 @tanstack/virtual。10000 条数据只渲染 20 条 DOM 节点,内存和性能都大幅优化。

代码分割

使用 React.lazy + Suspense 实现路由级代码分割。每个页面独立打包,按需加载。首屏加载体积减少 50%+,显著提升 FCP 和 LCP 指标。

JSX
// 优化示例:综合运用 memo + useMemo + useCallback
const ExpensiveList = React.memo(({ items, onSelect }) => {
  // 只在 items 变化时重新排序
  const sorted = useMemo(
    () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
    [items]
  );

  return (
    <ul>
      {sorted.map(item => (
        <li key={item.id} onClick={() => onSelect(item.id)}>
          {item.name}
        </li>
      ))}
    </ul>
  );
});

// 父组件中缓存回调
function Parent() {
  const [items, setItems] = useState([...]);
  const handleSelect = useCallback((id) => {
    console.log('Selected:', id);
  }, []); // 空依赖 → 函数引用不变

  return <ExpensiveList items={items} onSelect={handleSelect} />;
}
解读

性能优化的组合使用:

  • React.memo:浅比较 Props,跳过不必要的重新渲染
  • useMemo:缓存排序结果,只在 items 变化时重新计算
  • useCallback:缓存函数引用,配合 memo 使用
  • 三者配合:memo 检测 Props 变化 + useMemo 缓存数据 + useCallback 缓存函数

React Server Components

React Server Components(RSC)是 React 架构的重大演进。它允许组件在服务端运行,直接访问数据库和文件系统,同时保持 React 的组件化开发体验。

🚀
Server Components vs Client Components

Server Components:在服务端渲染,可以直连数据库、读取文件,不发送 JS 到客户端。Client Components:在客户端运行,可以使用 useState、useEffect、事件处理。通过 'use client' 指令标记。两者可以混合使用,Server Components 可以渲染 Client Components。

React.memo 的作用是什么?

React Server Components 的主要优势是什么?

05

总结与练习

回顾 React 核心知识,通过综合练习巩固技能,探索 React 生态系统

核心知识回顾

🧩

组件化架构

UI = f(state)。函数组件返回 JSX,Props 传递数据,State 管理内部状态。组件是独立、可复用的 UI 构建单元。遵循单一职责,每个组件不超过 100 行。

Hooks 体系

useState(状态)、useEffect(副作用)、useRef(引用)、useMemo(缓存计算)、useCallback(缓存函数)。Hooks 让函数组件拥有完整的 React 能力。遵循 Hooks 规则:只在顶层调用,不在条件语句中使用。

📈

性能优化

React.memo + useMemo + useCallback 三件套。虚拟列表处理长列表。代码分割按需加载。不可变状态更新确保变化检测。先测量(React DevTools Profiler),再优化。

🌐

生态系统

Next.js(全栈框架)、React Router(路由)、Zustand(状态管理)、SWR(数据获取)、React Query(服务端状态)、React Native(移动开发)。按需选择,不要过度引入依赖。

React 开发最佳实践

📄 最佳实践清单
🧩 组件设计
1. 单一职责——每个组件只做一件事
2. 组件名用 PascalCase,props 名用 camelCase
3. 超过 100 行就考虑拆分
4. 提取可复用逻辑为自定义 Hook
🔄 状态管理
5. 状态尽量下沉到使用它的最低层级组件
6. 永远使用不可变方式更新状态
7. useState 用于局部状态,Context 用于跨组件共享
8. 复杂状态考虑 useReducer
📈 性能优化
9. 先用 React DevTools Profiler 测量,再优化
10. 虚拟列表处理超过 100 项的长列表
11. 路由级代码分割是标配
12. 不要过早优化——大多数组件不需要 memo

综合练习:构建任务管理应用

设计一个功能完整的任务管理应用,综合运用组件化、状态管理、性能优化和 API 集成。

🎯
练习目标

构建一个任务管理应用,具备以下功能:1) 添加、编辑、删除任务;2) 任务筛选(全部/进行中/已完成);3) 搜索功能;4) 数据持久化(localStorage);5) 性能优化(memo + useMemo)。

JSX — 练习模板
function TaskManager() {
  // TODO 1: 定义任务列表状态
  // TODO 2: 定义筛选条件状态
  // TODO 3: 定义搜索关键词状态

  // TODO 4: 实现添加任务
  const addTask = (text) => { /* ??? */ };

  // TODO 5: 实现切换完成状态
  const toggleTask = (id) => { /* ??? */ };

  // TODO 6: 用 useMemo 缓存筛选结果
  const filteredTasks = /* useMemo(...) */;

  return (
    <div>
      <TaskInput onAdd={addTask} />
      <TaskFilter value={filter} onChange={setFilter} />
      <TaskList tasks={filteredTasks} onToggle={toggleTask} />
    </div>
  );
}
练习提示

完成这个练习的建议:

  • TODO 1-3:三个 useState 分别管理任务列表、筛选和搜索
  • TODO 4:setTasks(prev => [...prev, newTask])
  • TODO 5:map + 展开运算符更新单个任务
  • TODO 6:useMemo 缓存 filter + search 的组合筛选结果

下一步学习方向

🚀

Next.js 全栈框架

React 的官方推荐框架。Server Components、App Router、API Routes、SSR/SSG 一体化。学习 Next.js 是 React 开发者的自然下一步。

📱

React Native

使用 React 语法开发原生 iOS 和 Android 应用。一次学习,全平台开发。Expo 框架让 React Native 开发更加简单。

🤖

React + AI

将 AI 能力集成到 React 应用中:流式输出(SSE)、AI 对话界面、智能表单、内容生成。Vercel AI SDK 是目前最流行的 React AI 集成方案。

React 的主要特点包括哪些?

React 性能优化的正确顺序是什么?

React 中处理副作用的 Hook 是什么?