1. Vue 和 React 的主要区别
| 对比维度 | Vue | React |
|---|---|---|
| 核心设计思想 | 渐进式框架,主打 MVVM 双向绑定,官方 API 开箱即用,上手门槛低 | 专注视图层的 UI 库,推崇单向数据流与函数式编程,核心理念为 UI = f(state) |
| 数据绑定方式 | 双向数据绑定(v-model 语法糖),视图修改自动同步到数据 |
严格单向数据流,视图变更需通过事件回调手动更新状态 |
| 响应式原理 | Vue2 基于 Object.defineProperty,Vue3 基于 Proxy 劫持数据,精准追踪依赖 |
基于不可变数据,通过 setState / useState 手动触发重渲染,靠引用变化判断更新 |
| 模板写法 | 采用 <template> 模板语法,贴近原生 HTML,学习成本低 |
采用 JSX 语法,完全基于 JavaScript 编写 UI,灵活度更高,与 JS 生态融合更好 |
| Diff 算法 | 采用双端对比的虚拟 DOM Diff 算法 | React 16 后引入Fiber 架构,以链表结构实现可中断、可优先级调度的 Diff 过程 |
| 生态与灵活性 | 官方提供 Router、Pinia 等完整全家桶,方案统一规范 | 生态开放灵活,状态管理、路由等均为社区方案,适合复杂大型项目定制化开发 |
2. JS 的事件循环机制
JavaScript 是单线程语言,事件循环(Event Loop)是其处理异步任务的核心机制,用于保证代码执行不阻塞,核心围绕调用栈和任务队列运行。
核心规则
- 同步代码直接进入调用栈依次执行,执行完毕后栈被清空。
- 异步代码会被挂起,等到触发时机(定时器到期、网络请求返回等),对应的回调函数会被推入任务队列。
- 当调用栈为空时,先清空所有微任务,再取出一个宏任务执行,如此循环往复。
任务分类
- 宏任务:整体 script 代码、
setTimeout、setInterval、I/O 操作、UI 渲染 - 微任务:
Promise.then/catch/finally、queueMicrotask、MutationObserver
完整执行顺序
- 执行全局同步代码(属于第一个宏任务)
- 同步代码执行完毕,调用栈清空
- 依次执行当前所有微任务,直到微任务队列清空
- 浏览器执行 UI 渲染(可选步骤)
- 取出下一个宏任务执行,回到步骤 2 循环
3. React 局部状态管理方式
局部状态指仅在单个组件或小范围组件树内生效的状态,不依赖全局状态库,常见方式如下:
组件基础内部状态
- 类组件:
this.state + this.setState() - 函数组件:
useState,最常用的局部状态 Hook,适合简单单一状态
- 类组件:
复杂局部状态
useReducer:适合状态逻辑复杂、多个子状态互相关联、下一个状态依赖上一个状态的场景,通过 reducer 函数统一管理状态更新逻辑
非渲染型局部状态
useRef:存储不需要触发组件重渲染的变量(如定时器 ID、DOM 引用、上一次的值等),值变更不会引发重渲染
组件树局部共享状态
- 状态提升:将多个子组件的共享状态提升到最近的共同父组件,通过 props 向下传递,适合层级较浅的共享场景
- Context API + useState/useReducer:在指定组件树范围内提供状态,避免 props 层层透传,属于局部范围的状态共享方案
4. React 性能优化手段
核心优化方向为减少不必要的重渲染和降低渲染计算量,常见手段如下:
渲染层面优化
- 类组件:使用
PureComponent或自定义shouldComponentUpdate,通过浅比较 props 和 state 跳过不必要的更新 - 函数组件:用
React.memo包裹组件,对 props 做浅比较,缓存组件渲染结果 - 缓存计算与函数
useMemo:缓存复杂计算的结果,避免每次渲染都重新计算useCallback:缓存函数引用,配合React.memo使用,避免子组件因函数引用变化而重渲染
- 状态拆分:把不相关的状态拆分为独立的 state,避免单个状态变更引发全组件重渲染
结构与交互优化
- 组件粒度拆分:将大组件拆分为职责单一的小组件,精准控制渲染范围
- 正确使用 key:列表渲染时使用唯一稳定的 key,提升 Diff 算法效率,禁止用数组 index 作为 key
- 长列表优化:使用
react-window/react-virtualized实现虚拟滚动,只渲染可视区域节点 - 代码分割:用
React.lazy + Suspense实现路由/组件的按需懒加载,减少首屏包体积 - React 18 并发优化:使用
useTransition、useDeferredValue区分紧急更新和非紧急更新,避免低优先级任务阻塞 UI 交互
编码习惯优化
- 避免在组件渲染函数中直接创建内联对象、内联函数作为 props
- 避免在渲染过程中执行副作用,统一放到
useEffect中 - 合理使用
useRef存储频繁变更且不需要触发渲染的值
5. React 子组件方法暴露给父组件调用的方式
核心思路是通过 ref 或回调注册让父组件拿到子组件的方法引用,常用方案有三种:
ref 直接获取(仅适用于类组件)
类组件存在实例对象,父组件通过createRef创建 ref 并绑定到子组件上,即可通过ref.current直接调用子组件实例上的方法。forwardRef + useImperativeHandle(函数组件官方标准方案)
函数组件没有实例,不能直接通过 ref 获取方法,需两步实现:- 子组件用
forwardRef包裹,接收父组件传入的 ref - 子组件内部用
useImperativeHandle自定义暴露给父组件的方法和属性
该方案可控性强,是函数组件场景下的最推荐方案。
- 子组件用
props 回调注册法
父组件通过 props 传递一个注册函数给子组件,子组件在挂载时(useEffect)将自身的方法作为参数传入该回调,父组件保存方法引用后即可调用。适合场景简单、不想使用 ref 的情况。
React Fiber 简单介绍
Fiber 是 React 16 推出的全新协调引擎(Reconciler),核心目标是解决旧版同步渲染阻塞主线程的卡顿问题,让 React 的更新过程变得可中断、可恢复、可按优先级调度。
1. 诞生背景
React 15 及更早版本采用「Stack Reconciler」,通过递归遍历虚拟 DOM 树做 Diff 比对,整个更新过程是同步且不可中断的。一旦组件树庞大、更新计算耗时过长,就会阻塞浏览器主线程,导致用户输入、动画、页面滚动出现掉帧和卡顿。
2. 核心设计与实现
任务分片 + 链表结构
将整个渲染更新任务拆分为一个个细小的「Fiber 工作单元」,每个 Fiber 节点对应一个组件,以链表形式组织(包含child子节点、sibling兄弟节点、return父节点三个指针),替代了原本的递归遍历。任务可以随时暂停,后续从中断点继续执行,不再依赖浏览器调用栈。时间片调度
配合 Scheduler 调度器,在浏览器的空闲时间片内执行 Fiber 任务;时间片耗尽后立刻暂停工作,把主线程交还给浏览器处理用户交互、UI 渲染等高优先级操作,避免页面假死。双缓存机制
同时维护两棵 Fiber 树:当前屏幕正在显示的current树,和后台正在计算更新的workInProgress树。所有更新计算完成后,才会一次性替换两棵树的引用,保证用户不会看到中间的不完整渲染状态。优先级调度
给不同更新赋予不同优先级(比如用户点击/输入是高优先级,异步数据加载更新是低优先级),高优先级任务可以打断正在进行的低优先级任务,优先响应用户感知强的交互。
3. 核心价值
Fiber 把原本同步阻塞的渲染流程,改造为异步可调度的协作式任务系统,在不改变 React 开发体验的前提下,大幅提升了复杂大型应用的页面流畅度和交互响应性。
Redux 的核心作用
Redux 是一款可预测的 JavaScript 状态容器,是 React 生态中最主流的全局状态管理方案,核心用于集中管理应用的共享状态,规范状态更新流程,提升大型项目的可维护性。
1. 集中管理全局共享状态
解决 React 组件间跨层级通信、兄弟组件状态共享的痛点,避免 props 层层透传(Prop Drilling)问题。
将应用中通用的全局状态(如用户登录信息、主题配置、购物车数据、全局弹窗状态等)统一存储在唯一的 Store 中,项目内任意组件均可直接订阅、读取状态。
2. 规范状态更新,保证可预测性
遵循严格的单向数据流原则,状态更新必须遵循固定流程:dispatch(action) → reducer 纯函数计算 → 返回新 state
禁止直接修改状态,所有状态变更都有迹可循;配合 Redux DevTools 可以回溯、复现每一次状态变化,大幅降低复杂业务的调试成本。
3. 解耦状态逻辑与 UI 组件
将业务状态逻辑、副作用逻辑从组件中抽离,统一放到 action、reducer、中间件中维护。
组件仅负责「订阅状态渲染UI」和「触发action更新状态」,职责更单一,在大型项目中更易拆分、测试与迭代。
4. 生态适配复杂业务场景
通过配套中间件扩展能力,覆盖复杂业务需求:
- 异步处理:通过
redux-thunk/redux-saga管理接口请求等异步副作用 - 工程简化:官方推荐的
Redux Toolkit (RTK)大幅减少样板代码,内置不可变更新、状态切片、数据缓存(RTK Query)等能力 - 中间件扩展:支持日志、持久化、权限拦截等自定义扩展能力
支持我,让我有更多动力写出更好的文章