Skip to content

React 框架

专题版块详见 React 专题

认知 7 问:React

  1. 这是什么?

    • React 是一个由 Facebook 开发和维护的开源 JavaScript 库,专注于构建用户界面的视图库。React 主要用于构建单页面应用(SPA)中的视图层,支持组件化开发,强调“声明式编程”和“虚拟 DOM”。
  2. 它有什么用?

    • React 用于创建高效、动态和响应式的用户界面。它通过组件化的方式将 UI 拆分为独立的模块,使得开发者能够重用代码、管理应用状态,并在不直接操作 DOM 的情况下高效更新视图。
  3. 为什么需要它?

    • React 提供了灵活且高效的方式来更新视图,特别适合需要频繁和高效更新的 UI。通过虚拟 DOM,React 仅在状态变化时重新渲染必要的部分,优化了性能并减少了直接操作 DOM 的成本。
  4. 它的核心原理是什么?

    • React 的核心原理包括:
      • 组件化:React 应用通过组件化方式组织 UI,每个组件都有自己的状态和生命周期。
      • 虚拟 DOM:React 在内存中构建虚拟 DOM,避免直接操作真实 DOM,提高了更新效率。
      • 声明式编程:开发者通过声明 UI 应该如何呈现,React 会根据应用的状态来自动更新视图。
      • 单向数据流:React 中的数据流是单向的,父组件通过 props 将数据传递给子组件,子组件通过事件处理程序将数据传递回父组件。
  5. 它有哪些优缺点?

    • 优点
      • 高效的虚拟 DOM:减少了直接 DOM 操作,提高了性能。
      • 组件化开发:增强了代码复用性和维护性。
      • 灵活性:React 可以与其他库(如 Redux 或 MobX)集成,用于更复杂的状态管理。
      • 活跃的社区和生态:大量的开源组件、工具和库支持,使得 React 成为流行的选择。
    • 缺点
      • 学习曲线:React 的 JSX 语法、虚拟 DOM 和状态管理等概念需要一定的学习时间。
      • 配置复杂:React 本身只是视图库,复杂的应用通常需要搭配其他库(如 React Router、Redux)使用,这可能增加项目的复杂性。
      • 频繁更新:React 的快速更新迭代有时会导致向后兼容性问题,开发者需要保持对新版本的关注。
  6. 在哪些情况下使用最合适?

    • React 适用于构建复杂的、交互性强的单页面应用(SPA),特别是需要动态数据交互和频繁更新视图的应用。适合中大型项目和跨平台开发(例如使用 React Native 开发移动应用)。
  7. 未来的发展方向是什么?

    • 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 的核心特性

  1. 组件化开发:将 UI 拆分为独立的组件,提升代码复用性和维护性。
  2. 声明式编程:通过状态驱动视图更新,减少对 DOM 的直接操作。
  3. 虚拟 DOM:避免频繁操作真实 DOM,优化性能。
  4. 单向数据流:数据在组件树中自上而下流动,逻辑清晰。
  5. 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 中。
jsx
// 简化版 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 会暂停当前任务。
  • 优先级调度
    • 通过 requestIdleCallbackMessageChannel 检查主线程空闲时间。
    • 根据任务的优先级决定是否执行或暂停。
  • 双缓存树
    • 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.memouseMemo

虚拟 DOM 是什么?

  • 虚拟 DOM 是什么?
    • 虚拟 DOM 是一个轻量级的 JavaScript 对象,描述了 DOM 的结构。
    • 它是对真实 DOM 的抽象,可以被认为是一个“中间层”。
  • 工作流程:
    • 创建虚拟 DOM:通过 JSX 或 React.createElement 创建虚拟 DOM。
    • Diff 算法:比较新旧虚拟 DOM 树,找出需要更新的部分。
    • Patch 更新:将差异应用到真实 DOM,仅更新必要的节点。
  • 性能优化点:
    • 最小更新:通过 Diff 算法定位变化部分,避免整棵 DOM 树重新渲染。
    • 批量更新:合并多次状态变更导致的更新,减少操作频率。
js
// 一个简单的虚拟 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 的生命周期钩子的组合,可以用来模拟 componentDidMountcomponentDidUpdatecomponentWillUnmount
  • 自定义 Hooks:将通用逻辑抽离为独立函数,提升代码复用性。
    • 自定义 Hooks 的命名应以 use 开头,例如 useFetch
    • 在多个组件中复用逻辑时,优先考虑封装为自定义 Hooks。
jsx
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 性能优化

  1. 避免不必要的重渲染:使用 React.memoshouldComponentUpdate
  2. 代码分割:通过 React.lazySuspense 实现延迟加载。
  3. 状态管理优化:对大型应用使用 Redux,简化复杂状态的处理。

3. 学习与开发实践

3.1 学习路径

  1. 阅读官方文档:React 官方文档
  2. 观看实战课程:React - The Complete Guide
  3. 参与社区项目:在 GitHub 上查找 React 开源项目。

3.2 必备开发技能

  1. JSX:掌握 JSX 的语法与条件渲染。
  2. 组件生命周期:理解挂载、更新与卸载阶段的逻辑。
  3. 路由管理:使用 React Router 实现动态路由。
  4. 状态管理:熟练使用 Redux 或 Context API。
  5. 测试:用 React Testing Library 进行单元测试。

3.3 项目实践

  1. 基础项目:Todo List 应用
    • 学习事件处理与组件状态管理。
  2. 中级项目:电商商品展示
    • 实现动态数据加载、分页与筛选。
  3. 进阶项目:完整的单页面应用
    • 使用路由、全局状态管理与性能优化工具。

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 是一个强大且灵活的框架,通过深入理解其核心原理和最佳实践,可以帮助开发者高效构建现代化的用户界面。