第2章 React核心基础高频面试题:JSX原理、虚拟DOM、生命周期、事件机制
本章定位:跨端开发面试中,React核心基础是必考模块。掌握JSX编译原理、虚拟DOM diff策略、生命周期与Hooks映射、合成事件机制,是回答80%基础题的底层能力。
一、核心知识结构速览
| 面试主题 | 核心考点 | 跨端侧重点 |
|---|---|---|
| JSX原理 | 编译为React.createElement、babel插件、React.Children | RN中JSX同样编译为原生视图树 |
| 虚拟DOM | diff算法(同层/key/Fiber)、调和过程 | 跨端需了解React Native的Shadow Tree |
| 生命周期 | Class组件三阶段(挂载/更新/卸载)、Hooks替代方案 | RN中onLayout对应didMount;useEffect清理 |
| 事件机制 | 合成事件、事件委托、原生事件混用 | RN中触摸事件需用PanResponder/Gesture Handler |
二、知识结构图:JSX编译与虚拟DOM流程
三、面试问答卡片
❓ 面试问题:JSX 是如何被浏览器识别的?React 为什么选择 JSX?
| 考察点 | 编译原理、React.createElement 签名、babel 作用、跨端差异性 |
| 回答框架 | ① JSX 是语法糖→② Babel 编译为 React.createElement(type, props, ...children)→③ createElement 返回虚拟DOM对象→④ 优势:声明式、可组合、类型安全。跨端中 JSX 编译为原生视图树。 |
| 示例回答 | JSX 不是合法 JS,需 Babel 转译。例如 <div className="box">Hi</div> 编译为 React.createElement('div', { className:'box' }, 'Hi')。它让 UI 结构更直观,跨端时 RN 用同样 JSX 生成原生组件。 |
| 可能追问 | JSX 中 “{}” 表达式如何编译?为什么组件首字母必须大写?React.Children 有什么用? |
| 避坑提醒 | 不要答“JSX 是模板引擎”,避免说“必须用 JSX”其实是可选的(createElement 直接写)。跨端面试需强调 RN 中 JSX 编译为原生视图而非 DOM。 |
❓ 面试问题:虚拟 DOM 比真实 DOM 快吗?diff 算法如何工作?
| 考察点 | 虚拟DOM设计目的、diff策略(同层/key/Fiber)、性能本质、跨端渲染 |
| 回答框架 | ① 不一定更快,核心是“最小化DOM操作”→② diff 规则:同层比较、key 复用、type 不同直接替换→③ Fiber 实现可中断调和→④ 跨端 RN 对应 Shadow Tree 批量更新。 |
| 示例回答 | 虚拟DOM通过批量diff减少重排重绘。diff采用广度优先同层比较,当type变化直接替换整子树;key帮助列表复用。React Fiber将任务切片,高优先级先执行。RN中虚拟DOM对应Shadow Tree,由Yoga布局引擎计算。 |
| 可能追问 | 为什么不直接用索引当 key?Fiber 双缓冲如何工作?React 17/18 diff 有变化吗? |
| 避坑提醒 | 不要说“虚拟DOM更快”——对极简页面反而慢。避免忘记提 Fiber 的引入改变了 diff 的中断机制。跨端需补充 Yoga 布局到原生视图的映射。 |
❓ 面试问题:React 16+ 生命周期有哪些变化?Hooks 下如何替代 class 组件生命周期?
| 考察点 | 废弃的API(componentWillMount等)、useEffect模拟、合成事件原理 |
| 回答框架 | ① 挂载:constructor→render→componentDidMount(Hooks:useEffect([]))→② 更新:shouldComponentUpdate→render→componentDidUpdate(Hooks:useEffect(()=>{},[deps]))→③ 卸载:componentWillUnmount(Hooks:useEffect return 清理)→④ 合成事件:委托到根节点,提供跨平台兼容。 |
| 示例回答 | React 16 废弃了 componentWillMount 等生命周期,改用 getDerivedStateFromProps 和 getSnapshotBeforeUpdate。Hooks 中 useEffect 第二个参数控制执行时机;返回清理函数代替 componentWillUnmount。合成事件统一对事件进行池化,RN 中由触摸事件系统处理。 |
| 可能追问 | useEffect 与 useLayoutEffect 的区别?合成事件为什么要在 React 17 中绑定到 root 而非 document?RN 中如何阻止手势冒泡? |
| 避坑提醒 | 不要混淆 useEffect 和 class 生命周期的对应(useEffect 是异步的,useLayoutEffect 同步)。避免说“合成事件完全替代原生事件”——有时需要 e.nativeEvent。跨端面试需强调 RN 中没有 DOM 事件对象,而是原生触摸事件。 |
💡 本章高频追问总结:
• JSX -> 为何不能用 class 属性?(className 因 class 是保留字)
• 虚拟 DOM -> 手写一个简单的 diff 算法伪代码?
• 生命周期 -> useEffect 第二个参数为 [] 和 [a,b] 时分别如何执行?
• 事件机制 -> e.stopPropagation() 在合成事件中能阻止原生事件吗?(不能,需调用 e.nativeEvent.stopImmediatePropagation)
• JSX -> 为何不能用 class 属性?(className 因 class 是保留字)
• 虚拟 DOM -> 手写一个简单的 diff 算法伪代码?
• 生命周期 -> useEffect 第二个参数为 [] 和 [a,b] 时分别如何执行?
• 事件机制 -> e.stopPropagation() 在合成事件中能阻止原生事件吗?(不能,需调用 e.nativeEvent.stopImmediatePropagation)
🏆 章节能力模型:掌握本章4个核心模块,不仅能应对字节、腾讯、阿里等大厂基础面试,也为后续跨端章节(React Native / Taro / Flutter)打下底层认知。建议结合手写代码练习:实现一个简版 JSX 编译输出、模拟虚拟DOM diff 逻辑。