React Hooks 与前端编程模型:从 DOM 操作到 Web Worker

React Hooks 与前端编程模型:从 DOM 操作到 Web Worker

React 的出现在很大程度上改变了前端开发的思维方式。本文将围绕 React 常用 Hooks、DOM 编程的演进、以及 JavaScript 的异步机制展开讨论,帮助你建立起更完整的前端知识体系。


一、React 常用 Hooks 概览

useState ------ 响应式状态

useState 是 React 中最基础的 Hook,用于在函数组件中声明响应式状态。当状态发生变化时,React 会自动重新渲染组件,确保 UI 与数据保持同步。

jsx 复制代码
const [count, setCount] = useState(0);

useEffect ------ 副作用处理

useEffect 用于处理组件中的副作用,比如数据请求、订阅事件、操作 DOM 等。它在组件渲染完成后执行,避免了在渲染阶段执行副作用带来的问题。

jsx 复制代码
useEffect(() => {
  document.title = `点击了 ${count} 次`;
}, [count]);

useRef ------ 可变对象

useRef 是本文的重点。它提供一个持久可变对象,具有以下特点:

  • 可变但不触发渲染 :修改 ref.current 不会导致组件重新渲染。
  • 绑定 DOM 对象 :通过 ref 属性将 DOM 节点与 useRef 关联。
jsx 复制代码
const inputRef = useRef(null);

// JSX 中绑定
<input ref={inputRef} />

// 通过 current 访问 DOM 节点
inputRef.current?.focus();

二、DOM 编程的过去与现在

原生 DOM 编程的困境

在 React 和 Vue 出现之前,前端开发主要依赖原生 JavaScript 进行 DOM 操作。这种方式有两个天然的性能瓶颈:

  1. JS 运行在 V8 引擎,DOM 在渲染引擎:两个引擎之间的通信是有成本的,频繁的跨引擎操作会导致性能下降。
  2. 直接操作 DOM 非常消耗性能:每次修改 DOM 都可能触发浏览器的重排(reflow)和重绘(repaint),在大规模应用中尤为明显。

React 如何改变这一切

React 通过以下方式直接在架构层面规避了 DOM 编程

  • 数据绑定 + 响应式编程:开发者只需要关心数据(state),React 框架负责将数据映射到 DOM。
  • 虚拟 DOM:React 在内存中维护一棵虚拟 DOM 树,通过 diff 算法计算出最小的 DOM 操作,批量更新真实 DOM。

这种范式的转变,让前端开发的关注点从"如何操作 DOM"转向了"如何管理数据状态"。


三、当你确实需要操作 DOM 时

React 并非完全禁止 DOM 操作,而是将 DOM 操作的权利交给框架本身。但在某些场景下,开发者仍然需要直接访问 DOM 节点(例如:聚焦输入框、测量元素尺寸、集成第三方非 React 库)。

这时 useRef 就是 React 提供的"后门":

jsx 复制代码
function App() {
  const divRef = useRef(null);

  useEffect(() => {
    // 在需要的时候访问原生 DOM
    console.log(divRef.current?.getBoundingClientRect());
  }, []);

  return <div ref={divRef}>Hello World</div>;
}

核心步骤就两步:

  1. useRef 声明一个可变对象,初始值为 null
  2. 在 JSX 中通过 ref 属性将 DOM 元素绑定到该对象上。

之后,ref.current 就指向了这个真实的 DOM 节点。


四、useState 与 useRef 对比

特性 useState useRef
关注点 数据状态、业务逻辑 DOM 对象引用
响应式 是(触发重新渲染) 否(不触发重新渲染)
用途 驱动 UI 的数据 持久化可变引用
修改方式 setState 函数 直接修改 .current

总结定义

useRef 是 React 提供的一个持久可变对象的 Hook,常用于引用 DOM 节点。它有一个 current 属性,可以指向任意值或对象,修改它不会触发组件重新渲染。


五、JavaScript 为什么是单线程

JavaScript 被设计为单线程语言,这源于它的核心使命------处理前端页面交互。单线程确保了操作的一致性:同一时刻只有一个操作在执行,不会出现多个线程同时修改同一个 DOM 带来的冲突问题。

对于简单的脚本工作和页面交互来说,单线程模型简单可靠,不会出问题。


六、Event Loop ------ 异步无阻塞的秘诀

当一个页面变得复杂,存在大量任务或耗时操作时,单线程容易卡死。这时就需要 Event Loop(事件循环) 机制:

  • 同步任务在主线程上直接执行。
  • 异步任务(如网络请求、定时器)被挂起,等待时机成熟后通过回调队列推入主线程。

这种机制确保了前端能够尽快响应用户交互,而不被耗时任务阻塞。


七、Web Worker ------ 当 Event Loop 也不够用时

像 LLM 推理、游戏逻辑、大规模数据处理这类非界面相关的业务逻辑,即使放到异步队列中,依然会占用主线程的计算时间,导致页面卡顿。

这时 Web Worker 登场了:

  • Worker 使用浏览器独立开辟的内存空间
  • 在独立的线程中运行,与主线程并行执行。
  • 完成复杂计算后,通过 postMessage 将结果发送回主线程。
js 复制代码
// 主线程
const worker = new Worker(
  new URL('./worker.js', import.meta.url)
);

worker.onmessage = (e) => {
  console.log('Worker 计算结果:', e.data);
};

worker.postMessage({ type: 'heavy-computation', data: largeArray });

Web Worker 让 JavaScript 在保持单线程模型简洁性的同时,获得了处理复杂计算任务的能力------这是现代前端应对高性能场景的关键手段。


总结

useState 的响应式数据绑定,到 useRef 的 DOM 引用,再到 Event Loop 的异步调度,最后到 Web Worker 的多线程计算能力------这条技术脉络展示了前端开发的演进方向:让框架处理繁琐的 DOM 操作,让开发者聚焦业务逻辑,让合适的机制处理不同类型的计算任务

理解这些概念之间的关系,能够帮助我们在面对不同的场景时,选择最合适的工具和方案。

相关推荐
无人生还1 小时前
从 Vue3 到 React · 快速上手系列第 13 篇:工程化与综合实战(Vite + Todo 应用)
前端·vue.js·react.js
breeze jiang2 小时前
React useRef 实战:从 input 聚焦到 Web Worker 引用
前端·javascript·react.js
Rysxt_4 小时前
React vs Vue.js:2025年两大主流前端框架深度对比教程
vue.js·react.js·前端框架
by__csdn4 小时前
Vue vs React vs Angular:前端框架终极对决
前端·vue.js·react.js·前端框架·vue·react·angular
烬羽12 小时前
上来就用 useState?你大概率用错了——useRef 的三种正确打开方式
react.js·前端框架·全栈
光影少年13 小时前
RN的Fabric 渲染流程
运维·前端·javascript·react native·react.js·fabric
烬羽14 小时前
《React Router 受保护路由的 3 个坑,第 2 个 90% 的人都踩过》
react.js·性能优化·全栈
__zRainy__14 小时前
React开始:直接在网站中使用React.js
前端·react.js·前端框架
触底反弹17 小时前
🚀 20 行代码手写前端路由 + React Router 核心 API 一篇搞定!
前端·javascript·react.js