React 框架
专题版块详见 React 专题。
认知 7 问:React
这是什么?
- React 是一个由 Facebook 开发和维护的开源 JavaScript 库,专注于构建用户界面的视图库。React 主要用于构建单页面应用(SPA)中的视图层,支持组件化开发,强调“声明式编程”和“虚拟 DOM”。
它有什么用?
- React 用于创建高效、动态和响应式的用户界面。它通过组件化的方式将 UI 拆分为独立的模块,使得开发者能够重用代码、管理应用状态,并在不直接操作 DOM 的情况下高效更新视图。
为什么需要它?
- React 提供了灵活且高效的方式来更新视图,特别适合需要频繁和高效更新的 UI。通过虚拟 DOM,React 仅在状态变化时重新渲染必要的部分,优化了性能并减少了直接操作 DOM 的成本。
它的核心原理是什么?
- React 的核心原理包括:
- 组件化:React 应用通过组件化方式组织 UI,每个组件都有自己的状态和生命周期。
- 虚拟 DOM:React 在内存中构建虚拟 DOM,避免直接操作真实 DOM,提高了更新效率。
- 声明式编程:开发者通过声明 UI 应该如何呈现,React 会根据应用的状态来自动更新视图。
- 单向数据流:React 中的数据流是单向的,父组件通过 props 将数据传递给子组件,子组件通过事件处理程序将数据传递回父组件。
- React 的核心原理包括:
它有哪些优缺点?
- 优点:
- 高效的虚拟 DOM:减少了直接 DOM 操作,提高了性能。
- 组件化开发:增强了代码复用性和维护性。
- 灵活性:React 可以与其他库(如 Redux 或 MobX)集成,用于更复杂的状态管理。
- 活跃的社区和生态:大量的开源组件、工具和库支持,使得 React 成为流行的选择。
- 缺点:
- 学习曲线:React 的 JSX 语法、虚拟 DOM 和状态管理等概念需要一定的学习时间。
- 配置复杂:React 本身只是视图库,复杂的应用通常需要搭配其他库(如 React Router、Redux)使用,这可能增加项目的复杂性。
- 频繁更新:React 的快速更新迭代有时会导致向后兼容性问题,开发者需要保持对新版本的关注。
- 优点:
在哪些情况下使用最合适?
- React 适用于构建复杂的、交互性强的单页面应用(SPA),特别是需要动态数据交互和频繁更新视图的应用。适合中大型项目和跨平台开发(例如使用 React Native 开发移动应用)。
未来的发展方向是什么?
- React 将继续优化性能,改善开发者体验,并增强与现代前端开发技术(如 Web Components、Server-Side Rendering 等)的集成。React 的未来发展还包括对并发渲染、React Hooks 和 Suspense 等新特性的强化,使开发者能够更方便地管理异步数据和优化渲染流程。
1. React 的基本认知
1.1 React 是什么?
React 是由 Facebook 开发的开源 JavaScript 库,专注于构建用户界面的视图库。它通过 组件化 和 声明式编程 的方式,帮助开发者高效构建动态、交互性强的用户界面。
1.2 React 的主要用途
- 构建 单页面应用 (SPA):通过组件更新局部视图,提高用户体验。
- 创建 高效的 UI 界面:使用虚拟 DOM 提升渲染性能。
- 提供 跨平台支持:结合 React Native 实现移动端开发。
1.3 React 的核心特性
- 组件化开发:将 UI 拆分为独立的组件,提升代码复用性和维护性。
- 声明式编程:通过状态驱动视图更新,减少对 DOM 的直接操作。
- 虚拟 DOM:避免频繁操作真实 DOM,优化性能。
- 单向数据流:数据在组件树中自上而下流动,逻辑清晰。
- React Hooks:提供函数式组件的状态与生命周期管理能力。
2. React 的核心原理
2.1 组件化设计
核心思想:将页面拆分为多个独立的组件,组件负责其特定部分的 UI 和逻辑。
实践技巧:
- 遵循 单一职责 原则,每个组件只处理单一功能。
- 使用组合代替继承,通过
props
建立父子组件通信。
2.1.1 React 的组件化设计底层实现的原理是什么?
1) 虚拟 DOM
- React 组件实际上是一个函数(或类),返回描述 UI 结构的对象(即虚拟 DOM)。React 使用这些对象生成真实 DOM 并维护更新。
2) Fiber 架构
- React 的底层通过 Fiber 架构实现可中断的渲染,按优先级逐步构建 UI,避免长时间的主线程阻塞。
3) 合成事件
- React 不直接绑定 DOM 事件,而是通过合成事件(SyntheticEvent)机制统一管理,提高性能并保证跨浏览器兼容性。
4) Diff 算法
- React 利用 Diff 算法比较新旧虚拟 DOM 树,计算需要更新的最小操作集合并应用到真实 DOM 中。
// 简化版 React 实现
class Component {
constructor(props) {
this.props = props;
}
setState(partialState) {
this.state = { ...this.state, ...partialState };
render(); // 模拟重新渲染
}
}
function createElement(tag, props, ...children) {
return { tag, props: props || {}, children };
}
function renderElement(vdom) {
if (typeof vdom === "string") {
return document.createTextNode(vdom);
}
const { tag, props, children } = vdom;
const element = document.createElement(tag);
// 设置属性
for (const key in props) {
if (key.startsWith("on")) {
element[key.toLowerCase()] = props[key]; // 事件绑定
} else {
element.setAttribute(key, props[key]);
}
}
// 渲染子节点:递归操作
children.forEach((child) => {
element.appendChild(renderElement(child));
});
return element;
}
function render(vdom, container) {
container.innerHTML = ""; // 简单清空重渲染
container.appendChild(renderElement(vdom));
}
// 示例:一个简单的组件
// 通过类 Counter 定义一个组件,每个组件拥有独立的 `state` 和 `render` 方法。
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return createElement(
"div",
null,
createElement("p", null, `Count: ${this.state.count}`),
createElement("button", { onClick: this.increment }, "Increment")
);
}
}
// 模拟 React.render
const app = createElement(Counter);
render(app.render(), document.getElementById("root"));
2.1.2 什么是 Fiber 架构?
Fiber 架构 是 React 自 16 版本引入的一种新的协调引擎,旨在优化渲染过程,支持更复杂的场景,如动画、流畅交互和大型应用的性能优化。
1)Fiber 架构的背景
- 渲染过程是不可中断的,如果组件树较大,更新操作可能导致浏览器卡顿,影响用户体验。
- JavaScript 在主线程中运行,长时间占用主线程会阻塞用户的交互(如点击、滚动等)。
2)Fiber 的核心理念
Fiber 的主要目标是:将渲染过程拆分为可以中断的小任务单元,从而更高效地管理渲染和更新。
- 时间分片(Time Slicing)
- React 将渲染工作拆分成许多小任务,并在任务之间检查主线程是否有空闲。如果主线程有其他更高优先级的任务(如用户交互),React 会暂停渲染工作,优先处理高优先级任务。
- 任务优先级
- React 为每个更新任务分配优先级,例如用户输入通常比非关键的动画更新优先级更高。
- 双缓冲更新机制
- React Fiber 实现了双缓冲更新,分别维护「当前」和「工作中」的树,确保更新的安全性。
3)Fiber 的核心数据结构
Fiber 是 React 中的一个数据结构,表示组件树中每个节点的工作单元。每个 Fiber 节点包含以下信息:
- 类型:节点是函数组件、类组件、原生 DOM 还是其他类型。
- props:节点的属性。
- stateNode:与 Fiber 节点关联的真实 DOM 或组件实例。
- child / sibling / return:指向子节点、兄弟节点和父节点,用于遍历 Fiber 树。
- 工作单元:描述当前任务的执行状态(如挂载、新增、删除等)。
4)Fiber 架构的渲染过程(渲染分为两个阶段)
- 协调阶段(Reconciliation)
- 构建虚拟 DOM 树并与当前 Fiber 树进行 Diff。
- 生成更新任务,标记需要更新的节点。
- 此阶段是异步的,可以中断。
- 提交阶段(Commit)
- 将协调阶段生成的更新任务应用到真实 DOM。
- 包括 DOM 的创建、更新和删除。
- 此阶段是同步的,不可中断。
5)Fiber 的实现特点
- 可中断渲染
- Fiber 树的遍历采用深度优先遍历,每次只执行一个任务单元。如果检测到主线程有更高优先级任务,React 会暂停当前任务。
- 优先级调度
- 通过
requestIdleCallback
或MessageChannel
检查主线程空闲时间。 - 根据任务的优先级决定是否执行或暂停。
- 通过
- 双缓存树
- React 维护了两棵 Fiber 树:Current Fiber Tree 和 Work-in-progress Fiber Tree。
- 「工作中的树」用于处理更新,「当前树」用于渲染真实 DOM。
- 在更新完成后,React 会将工作树替换为当前树。
2.1.3 费曼学习法理解 Fiber
用生活类比解释 Fiber
- 传统 React 更新(同步模式)
- 想象你在写一篇文章(页面渲染),但写到一半突然有人敲门(用户事件)。你不能停下手里的工作(同步阻塞),必须把整篇文章写完再去开门,导致敲门的人等得很焦急。
- Fiber 架构(异步模式)
- Fiber 架构让你可以在写文章时停下来,优先去开门处理紧急的事情,然后再回来继续写文章。这种机制让重要的事情不会被忽略,整体效率更高。
用代码理解 Fiber
- 传统模式下,任务会一口气完成:js
function render() { console.log("Rendering starts..."); for (let i = 0; i < 1000000; i++) { // 假设这是一个很耗时的任务 } console.log("Rendering ends."); } render(); // 页面卡住,直到任务完成。
- 在 Fiber 模式下,任务会被拆分:js
function renderPartially() { console.log("Rendering starts..."); let i = 0; function work() { // 每次只渲染 1000 个任务,然后暂停 for (let j = 0; j < 1000; j++) { i++; if (i >= 1000000) { console.log("Rendering ends."); return; } } // 暂停后再继续 requestIdleCallback(work); } work(); } renderPartially(); // 页面不会卡住,能及时响应用户操作。
requestIdleCallback
requestIdleCallback
是浏览器提供的一种方法,用来在主线程空闲时执行一些非紧急任务,比如性能优化、低优先级的后台任务等,而不会阻塞用户的交互操作。
它的基本作用是:
- 当主线程有空闲时间时,调用指定的回调函数。
- 避免阻塞高优先级任务(如用户输入、动画等),提高页面的流畅性。
2.2 虚拟 DOM
核心思想:React 使用虚拟 DOM 维护应用的视图状态,减少对真实 DOM 的直接操作。
实践技巧:
- 使用
key
属性优化动态列表的渲染效率。 - 避免不必要的重新渲染,使用
React.memo
和useMemo
。
虚拟 DOM 是什么?
- 虚拟 DOM 是什么?
- 虚拟 DOM 是一个轻量级的 JavaScript 对象,描述了 DOM 的结构。
- 它是对真实 DOM 的抽象,可以被认为是一个“中间层”。
- 工作流程:
- 创建虚拟 DOM:通过 JSX 或
React.createElement
创建虚拟 DOM。 - Diff 算法:比较新旧虚拟 DOM 树,找出需要更新的部分。
- Patch 更新:将差异应用到真实 DOM,仅更新必要的节点。
- 创建虚拟 DOM:通过 JSX 或
- 性能优化点:
- 最小更新:通过 Diff 算法定位变化部分,避免整棵 DOM 树重新渲染。
- 批量更新:合并多次状态变更导致的更新,减少操作频率。
// 一个简单的虚拟 DOM 结构示例
const virtualDOM = {
type: "div",
props: {
id: "container",
children: [
{ type: "h1", props: { children: "Hello, World!" } },
{ type: "p", props: { children: "This is a virtual DOM example." } },
],
},
};
虚拟 DOM 的实现,用了什么原理和设计模式?
1) 虚拟 DOM 的关键原理
- 虚拟化(抽象层)
- Diff 算法
- 批量更新机制
- 声明式编程
- 可预测性和一致性
2) 虚拟 DOM 的设计模式
相关代码详见 React 虚拟 DOM 的设计模式。
- 代理模式:通过代理对象来操作真实对象,实现虚拟 DOM 的操作。
- 观察者模式:通过观察者模式,实现虚拟 DOM 的更新通知。
- 策略模式:通过策略模式,实现虚拟 DOM 的不同更新策略。
- 单例模式:通过单例模式,实现虚拟 DOM 的全局唯一实例。
- 组合模式:通过组合模式,实现虚拟 DOM 的树状结构。
- 工厂模式:通过工厂模式,实现虚拟 DOM 的创建和管理。
- 装饰器模式:通过装饰器模式,实现虚拟 DOM 的扩展和增强。
- 命令模式:通过命令模式,实现虚拟 DOM 的操作封装和调度。
- 迭代器模式:通过迭代器模式,实现虚拟 DOM 的遍历和访问。
- 享元模式:通过享元模式,实现虚拟 DOM 的复用和共享。
- 原型模式:通过原型模式,实现虚拟 DOM 的继承和扩展。
- 适配器模式:通过适配器模式,实现虚拟 DOM 的兼容和转换。
- 模板方法模式:通过模板方法模式,实现虚拟 DOM 的抽象和复用。
- 中介者模式:通过中介者模式,实现虚拟 DOM 的解耦和协调。
- 状态模式:通过状态模式,实现虚拟 DOM 的状态管理和切换。
- 备忘录模式:通过备忘录模式,实现虚拟 DOM 的状态保存和恢复。
- 访问者模式:通过访问者模式,实现虚拟 DOM 的操作扩展和定制。
- 解释器模式:通过解释器模式,实现虚拟 DOM 的语法解析和执行。
2.3 单向数据流
VUE3 也遵循单向数据流的原则,父组件通过
props
向子组件传递数据,子组件通过emit
事件向父组件传递变化。另外,Vue 3 提供了 provide 和 inject 方法,适用于组件层级较深时的状态共享。
核心思想:React 中的数据流是单向的,父组件通过 props 传递数据,子组件通过事件将变化传递回父组件。
实践技巧:
- 对复杂的状态共享,使用 Context API 或 Redux。
- (VUE3)复杂场景:Vuex 或 Pinia
- 将状态提升到最近的公共父组件,避免重复逻辑。
2.4 React Hooks
核心思想:为函数组件提供状态和生命周期管理能力。
实践技巧:
- useState:管理局部状态。
- useEffect:处理副作用(如数据获取、订阅事件、手动操作 DOM 等)。
useEffect
是 React 的生命周期钩子的组合,可以用来模拟componentDidMount
、componentDidUpdate
和componentWillUnmount
。
- 自定义 Hooks:将通用逻辑抽离为独立函数,提升代码复用性。
- 自定义 Hooks 的命名应以
use
开头,例如useFetch
。 - 在多个组件中复用逻辑时,优先考虑封装为自定义 Hooks。
- 自定义 Hooks 的命名应以
import React, { useState, useEffect } from "react";
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
const interval = setInterval(() => setTime((t) => t + 1), 1000);
return () => clearInterval(interval); // 清理副作用
}, []); // 空依赖数组,表示仅在组件挂载和卸载时运行
// 备注:
// 1)空数组 []:只在组件挂载和卸载时运行。
// 2)有依赖 [dep1, dep2]:在依赖项发生变化时运行。
// 3)无依赖(省略数组):每次渲染后运行。
return <p>Elapsed Time: {time} seconds</p>;
}
export default Timer;
2.5 性能优化
- 避免不必要的重渲染:使用
React.memo
或shouldComponentUpdate
。 - 代码分割:通过
React.lazy
和Suspense
实现延迟加载。 - 状态管理优化:对大型应用使用 Redux,简化复杂状态的处理。
3. 学习与开发实践
3.1 学习路径
- 阅读官方文档:React 官方文档。
- 观看实战课程:React - The Complete Guide。
- 参与社区项目:在 GitHub 上查找 React 开源项目。
3.2 必备开发技能
- JSX:掌握 JSX 的语法与条件渲染。
- 组件生命周期:理解挂载、更新与卸载阶段的逻辑。
- 路由管理:使用
React Router
实现动态路由。 - 状态管理:熟练使用 Redux 或 Context API。
- 测试:用 React Testing Library 进行单元测试。
3.3 项目实践
- 基础项目:Todo List 应用
- 学习事件处理与组件状态管理。
- 中级项目:电商商品展示
- 实现动态数据加载、分页与筛选。
- 进阶项目:完整的单页面应用
- 使用路由、全局状态管理与性能优化工具。
4. React 的生态系统
4.1 常用工具
- 状态管理:Redux、MobX、Recoil。
- 路由管理:React Router。
- 数据请求:Axios、React Query。
- 性能优化:React DevTools、Lighthouse。
4.2 React Native
React Native 是 React 的衍生框架,用于构建跨平台的移动端应用,支持 iOS 和 Android。
4.3 Server-Side Rendering (SSR)
结合 Next.js 提升首屏渲染性能与 SEO 效果。
5. React 的未来方向
5.1 并发模式 (Concurrent Mode)
增强用户体验,支持更流畅的 UI 交互。
5.2 Server Components
通过服务端渲染减少客户端渲染压力,优化性能。
5.3 生态系统更新
React 社区将持续推出新的库与工具,增强开发效率。
React 是一个强大且灵活的框架,通过深入理解其核心原理和最佳实践,可以帮助开发者高效构建现代化的用户界面。