React 的核心思想是:当应用状态(State)发生变化时,框架自动计算出界面需要更新的最小范围,然后只更新那一部分真实 DOM。这套机制由 Virtual DOM(虚拟 DOM)和协调算法(Reconciliation)共同完成。
React 16 引入的 Fiber 架构将协调过程重构为可中断的链表结构,使渲染过程可以被优先级更高的任务(如用户输入)打断,从而提升交互响应速度。React 18/19 在此基础上进一步增强了并发渲染能力,支持时间切片(Time Slicing)和过渡更新(Transitions)。
函数组件是最基础也是当前最推荐的组件定义方式,本质是一个接收 Props 并返回 JSX 的普通 JavaScript 函数。React 16.8 引入 Hooks 后,函数组件已能完全替代类组件的所有功能,包括状态管理和副作用处理。
类组件通过 ES6 class 语法继承 React.Component 来定义,必须实现 render() 方法返回 JSX。类组件中通过 this.state 和 this.setState() 管理状态,通过生命周期方法(如 componentDidMount、componentDidUpdate)处理副作用。
this 指向问题;类组件需要 constructor 绑定和 this 处理,容易出现绑定错误useState、useReducer 等 Hooks;类组件使用 this.state 和 this.setState()useEffect 统一处理挂载、更新和卸载逻辑;类组件分散在 componentDidMount、componentDidUpdate、componentWillUnmount 等方法中React 官方和社区在2026 年的一致推荐是:所有新代码使用函数组件 + Hooks。类组件不会被移除,仍可用于维护旧项目,但新功能开发应优先采用函数组件方案。
React Hooks 于 React 16.8(2019 年)正式引入,允许在函数组件中使用状态和其他 React 特性,而无需编写类组件。Hooks 的本质是一些特殊的函数,它们让你"钩入"(Hook into)React 的状态管理和生命周期能力。
componentDidMount,无依赖数组则在每次渲染后执行,指定依赖则在依赖变化时执行React.memo 使用可防止子组件不必要重渲染useContext 的增强替代方案constructor 初始化状态 → render 渲染 → componentDidMount 挂载完成(适合发起网络请求、绑定订阅)shouldComponentUpdate 决定是否重渲染 → render 重新渲染 → componentDidUpdate 更新完成componentWillUnmount 清理定时器、取消订阅、移除事件监听类组件生命周期 | 函数组件 Hooks 替代方案 |
|---|---|
constructor 初始化状态 | useState 初始化状态 |
componentDidMount | useEffect 依赖数组为空 [] |
componentDidUpdate | useEffect 带依赖数组 [dep] |
componentWillUnmount | useEffect 返回清理函数 return () => {...} |
shouldComponentUpdate | React.memo 或 useMemo |
新项目应统一使用函数组件 + useEffect 模式。useEffect 的优势在于可以将"挂载时执行 + 更新时执行 + 卸载时清理"的逻辑整合在同一个函数中,避免类组件中生命周期方法分散的问题。
React 状态管理可分为多层次方案:组件局部状态(useState / useReducer)、跨组件状态(Context API)、以及独立的全局状态管理库(Redux、Zustand、MobX、Recoil 等)。选择取决于应用规模、团队经验和状态更新频率。
useStore 订阅状态;支持中间件(persist 持久化、devtools 调试、immer 不可变更新)2026 年的社区趋势是:新项目首选 Zustand(兼顾性能和开发效率);大型企业项目或有强调试需求时选择 Redux Toolkit;复杂表单/配置场景可考虑 MobX;纯服务端状态优先使用 TanStack Query(React Query)而非上述客户端状态库。
React Router 是一个基于 React 的多策略路由器,通过 History API 拦截浏览器导航行为,在客户端完成路由切换和组件渲染,无需向服务器发起整页请求。当用户点击 <Link> 组件时,React Router 阻止默认的页面跳转行为,更新 URL,并根据当前 URL 匹配对应的 <Route> 组件进行渲染。
React Router 通过 :paramName 语法支持动态路由段,在组件内通过 useParams() Hook 读取参数值。useSearchParams() 提供对 URL 查询字符串的读写能力,类似 useState 的 API 设计。
嵌套路由是 React Router 的核心特性,允许子路由在父路由的布局组件(Layout)内部渲染。父组件通过 <Outlet /> 组件指定子路由的渲染位置,实现稳定的侧边栏、导航栏与动态内容区的组合布局。
React Router v6/v7 中,传统的 onEnter 回调已被更强大的 Loader 机制替代。路由守卫通过在路由配置中定义 loader 函数来实现:在渲染前执行鉴权检查,未登录用户通过 throw redirect('/login') 重定向到登录页,登录后可通过 location.state 回跳原目标页面。
React Router v7(2024 年末稳定发布,2026 年为主流版本)融合了 Remix 框架的能力,新增 Loader(数据加载)、Action(表单提交处理)、useNavigation()(导航状态监听)等 API,支持数据预加载和并行加载,大幅提升嵌套路由场景下的加载性能。
通过 React.lazy() 和 <Suspense> 实现组件级代码分割,将不同路由对应的页面拆分为独立的 JS 包,首屏只加载当前页面所需的代码。动态 import() 语法让大型库(如图表库、富文本编辑器)仅在真正需要时加载。
当渲染超过 200 条列表数据时,应使用虚拟化技术(如 @tanstack/react-virtual,即原 react-window)只渲染可视区域内的行,将 DOM 节点数量从数千个降低到 10-20 个,大幅提升滚动流畅度。
避免将频繁变化的状态放在全局 Context 中(每次 Context 值变化都会导致所有消费者重渲染)。应优先使用组件局部状态,全局状态只放置真正需要跨组件共享的数据(如主题、认证信息)。
React Compiler 是独立的构建时优化工具(2025年10月发布稳定版 v1.0),可配合 React 19 使用,能够自动分析组件代码并插入适当的记忆化指令,在多数场景下可替代手动编写 useMemo 和 useCallback 的需要,减少大量重渲染开销。
React 并不直接将事件处理函数绑定到 DOM 节点上,而是基于原生事件封装了一套跨浏览器兼容的事件系统,称为合成事件(SyntheticEvent)。当你在 JSX 中写 onClick={handler} 时,传递的并不是原生 DOM 事件,而是 React 封装的统一事件对象。
React 将所有事件统一委托到应用的根容器(React 17+ 为 #root 节点,React 17 之前为 document)进行监听,而非在每个 DOM 元素上单独绑定监听器。这种机制减少了内存开销,并解决了不同浏览器之间的事件行为差异问题。
以点击事件为例,完整的执行顺序为:原生捕获阶段(document → root → div → button)→ React 合成捕获阶段(父组件捕获 → 子组件捕获)→ React 合成冒泡阶段(子组件冒泡 → 父组件冒泡)→ 原生冒泡阶段(button → div → root → document)。
React 16 及更早版本中,合成事件对象会被放入"事件池"中复用,在异步回调(如 setTimeout)中访问事件字段会遇到空值,需调用 e.persist() 保留事件对象。React 17+ 已彻底废弃事件池机制,合成事件对象在事件处理函数执行完毕后即被垃圾回收,可在异步代码中安全访问。
在 React 中手动绑定原生事件(如 addEventListener)时,需在组件卸载前通过清理函数移除监听,否则会造成内存泄漏。合成事件和原生事件混用时,需清楚两者的执行顺序差异,避免出现预期外的交互行为。
Vue 的学习曲线最平缓(1-2 周可达到基本生产力),React 次之(2-4 周,主要是理解 JSX 和 Hooks 心智模型),Angular 最陡峭(4-8 周,需掌握 TypeScript、依赖注入、RxJS 等概念)。
React 拥有最大的生态系统(npm 上超过 250 万个包引用 React),招聘市场需求也最高;Angular 的生态较为完整但规模小于 React,主要由企业级应用场景驱动;Vue 的生态在快速增长,但高级开发者的人才供给相对紧张。
传统的 React 单页应用(SPA)在浏览器端完成所有渲染工作:先下载 JS 包,再执行渲染。这导致首屏出现"白屏"、搜索引擎爬虫难以获取页面内容(SEO 不友好)、低网络环境下加载体验差等问题。
SSR 在服务器端完成 React 组件的首次渲染,将生成的完整 HTML 发送给浏览器,浏览器直接展示内容后再"激活"(Hydrate)为可交互的 React 应用。这样用户无需等待 JS 执行即可看到页面内容,同时搜索引擎可以直接抓取到完整 HTML。
app/ 或 pages/ 目录结构自动生成路由,无需手动配置路由表React 和 Next.js 应用可部署于腾讯云 CloudBase 平台,其提供开箱即用的 SSR 支持、全球加速 CDN 和自动扩缩容能力,适合面向公网用户的商业级应用部署。
父组件向子组件传递数据通过 Props(属性)实现,子组件通过父组件传递的回调函数向父组件反馈信息。这是 React 中最基础也是最重要的通信方式,适用于直接父子关系的组件。
兄弟组件之间没有直接通信通道,需将共享状态"提升"到它们最近的共同父组件中,由父组件通过 Props 分别向两个子组件传递状态和回调函数,实现数据同步。
当组件层级较深(超过 3 层)时,通过 Props 逐层传递数据会产生"Prop Drilling"问题。Context API 允许在组件树中广播数据,任何层级的子组件都可以通过 useContext Hook 直接读取 Context 值,无需中间组件显式传递。
对于在多个不相关组件之间共享的状态(如用户登录信息、主题设置、购物车),使用独立的全局状态管理库是最合适的方案。这类工具提供统一的状态存储、可预测的状态更新和调试工具支持。
React.lazy() 接受一个动态 import() 函数作为参数,返回一个可延迟加载的 React 组件。Suspense 组件包裹懒加载组件,并指定加载过程中的降级 UI(如加载指示器)。当组件首次渲染时,React 自动发起 JS 包的下载,下载完成后再渲染组件。
将每个页面拆分为独立的 JS 包是代码分割中收益最高的手段。配合 React Router 使用时,每个路由对应的页面组件都应通过 React.lazy() 加载,这样用户访问不同页面时只下载当前页面所需的代码,可大幅减少初始包体积。
对于不是首屏必需的重型组件(如图表编辑器、富文本编辑器、模态框),应根据交互条件动态加载。例如:用户点击"编辑"按钮时才加载编辑器组件,避免所有访问者都提前下载编辑器的代码。
大型第三方库(如 Chart.js、Monaco Editor、PDF 处理库)应通过动态 import() 按需加载,而非在应用入口处全部导入。配合 React.lazy 或直接在事件处理函数中动态导入,可显著减少初始包体积。
使用 webpack-bundle-analyzer 或 Vite 的打包可视化工具分析最终生成的 JS 包组成,识别体积过大的模块和重复依赖。结合 Chrome DevTools 的 Coverage 面板(覆盖率分析)找出加载了但未实际执行的代码,针对性地进行懒加载处理。
高阶组件是一个函数,接收一个组件作为参数,返回一个新的增强版组件。HOC 的本质是在组件外层包裹一层"容器",通过 Props 注入、生命周期拦截或渲染控制来实现逻辑复用。常见应用场景包括:鉴权检查、日志记录、错误边界包装等。
自定义 Hook 是一个以 use 开头的 JavaScript 函数,内部可以调用其他 Hooks(如 useState、useEffect),将组件逻辑提取为可复用的独立函数。自定义 Hook 不创建额外的组件层级,逻辑直接在调用它的组件内部执行。
特性 | 高阶组件(HOC) | 自定义 Hooks |
|---|---|---|
实现方式 | 函数接收组件,返回新组件 | 函数调用 Hooks,返回状态或方法 |
组件树影响 | 增加组件层级(包装地狱) | 不增加组件层级 |
逻辑复用方式 | 通过包裹增强组件能力 | 通过调用函数复用状态逻辑 |
Props 传递 | 可能出现 Props 命名冲突 | 调用者自行命名返回值,无冲突 |
调试体验 | 组件树中显示多层包裹结构 | 组件树扁平,调试更清晰 |
适用组件类型 | 函数组件和类组件均可 | 仅限函数组件 |
React 官方和社区在 2025-2026 年的明确推荐是:优先使用自定义 Hooks 进行逻辑复用,HOC 仅用于特定场景(如需要包裹错误边界、需要兼容旧版类组件、第三方库要求使用 HOC 模式)。
componentDidCatch,需通过 HOC 包装实现connect())仍采用 HOC 模式React 应用的测试策略遵循测试金字塔原则:底层是大量的单元测试(快速、隔离、测试单个函数或组件),中间是有限的集成测试(测试多个模块协作),顶层是少量的端到端(E2E)测试(模拟真实用户操作流程)。
RTL 提供 render() 函数将组件挂载到虚拟 DOM 中,通过 screen.getByRole()、screen.getByText() 等方法查询元素,通过 @testing-library/user-event 模拟真实的用户交互(点击、输入、选择等),最后使用 Jest 的 expect() 断言验证行为是否符合预期。
自定义 Hooks 需要借助 @testing-library/react 提供的 renderHook() API 进行测试:在测试环境中渲染一个调用目标 Hook 的微型组件,然后通过返回值验证 Hook 的状态管理和副作用行为是否正确。
getBy* 查询必须存在的元素,使用 queryBy* 断言元素不存在,使用 findBy* 处理异步出现的元素jest --coverage 生成测试覆盖率报告,目标覆盖核心业务逻辑和边界条件