[20250119]-前端面试题——React篇
面试问题记录
问题 1
请简单介绍一下React18有哪些更新。
回答:
React 18 的主要更新包括:
- 并发渲染:React 18 引入了并发渲染(Concurrent Rendering),使得 React 能在后台进行渲染工作,避免阻塞 UI 更新,提升性能。
- 自动批处理:React 18 会自动批处理多次
setState
更新,减少不必要的渲染,提升性能。 useId
Hook:提供一个生成唯一 ID 的 Hook,帮助解决 SSR(服务器端渲染)中的 ID 不一致问题。startTransition
API:允许开发者将某些更新标记为低优先级,确保高优先级的渲染不被阻塞。- Suspense 支持 SSR:
Suspense
现在支持服务端渲染(SSR),使得异步组件加载更加平滑。
这些更新提升了 React 的性能和开发体验,特别是在处理复杂 UI 和异步渲染时。
问题 2
JSX是什么,它和JS有什么区别?
回答:
JSX 是 JavaScript 的语法扩展,用于在 React 中描述 UI 结构,看起来像 HTML,但最终会被编译为 JavaScript 代码(如 React.createElement
调用)。
JSX 和 JS 的区别
- 语法:JSX 类似 HTML,嵌套在 JS 中;JS 是标准 JavaScript 语法。
- 功能:JSX 用于定义 React 组件的 UI;JS 用于逻辑控制和操作。
- 处理:JSX 需编译为 JS 才能运行;JS 可直接运行。
- 表达式:JSX 支持在
{}
中嵌入动态 JS 表达式。
问题3
请说一下React 事件机制和JS原生事件机制的区别
回答:
React 事件机制和 JS 原生事件机制的区别
React 的事件机制是对浏览器原生事件机制的一层封装,主要区别如下:
1. 事件绑定方式
-
React:
React 使用合成事件 (SyntheticEvent
) 统一处理跨浏览器的事件兼容性。- 所有事件都通过虚拟 DOM 绑定在顶层容器(如
document
或root
节点)。 - React 内部通过事件委托机制来管理事件监听,减少 DOM 事件绑定的数量。
示例:
<button onClick={() => console.log('React event')}>Click Me</button>
- 所有事件都通过虚拟 DOM 绑定在顶层容器(如
-
JS 原生:
原生事件绑定在具体的 DOM 元素上。可以选择直接在 HTML 中写内联事件,或通过 JavaScript 使用addEventListener
绑定事件。示例:
const button = document.querySelector('button'); button.addEventListener('click', () => console.log('Native event'));
2. 事件模型
- React:
React 的事件绑定在顶层,通过事件冒泡机制和事件委托捕获事件。React 的事件模型不会直接操作真实 DOM,而是通过虚拟 DOM 映射真实 DOM。- React 中的事件冒泡阶段发生在虚拟 DOM 层面。
- 事件可以被
stopPropagation()
和preventDefault()
拦截,但影响的是合成事件。
- JS 原生:
原生事件模型分为 捕获阶段、目标阶段 和 冒泡阶段,直接绑定在真实 DOM 上。
3. 事件对象
-
React:
React 的事件对象是SyntheticEvent
,这是对原生事件对象的封装,提供了跨浏览器的统一接口。- 属性和方法与原生事件类似,但不完全一致。
SyntheticEvent
是轻量的,会被回收,因此不能异步访问。
示例:
const handleClick = (e) => { console.log(e.nativeEvent); // 原生事件对象 console.log(e); // React SyntheticEvent };
-
JS 原生:
原生事件对象直接提供浏览器的Event
对象,包含原生 DOM 事件信息。
4. 事件解绑
-
React:
React 的事件绑定和解绑由内部机制管理,无需手动移除监听器。- 当组件卸载时,React 会自动清理事件,避免内存泄漏。
-
JS 原生:
原生事件需要手动移除监听器,否则可能会造成内存泄漏。
示例:const handleClick = () => console.log('Clicked'); button.addEventListener('click', handleClick); button.removeEventListener('click', handleClick);
5. 事件委托
- React:
React 内部默认使用事件委托,将所有事件绑定在顶层容器上(如document
)。- 因此,不需要手动实现事件委托,子元素的事件冒泡会被 React 捕获并处理。
- JS 原生:
如果需要事件委托,需手动绑定事件到父元素并通过事件冒泡机制进行处理。
6. 性能
- React:
- 通过事件委托减少了 DOM 事件绑定数量,提高性能。
- React 事件封装有轻微性能开销,但一般可以忽略。
- JS 原生:
- 大量事件绑定在不同元素上可能会影响性能。
- 更加灵活,但需要手动优化。
总结
对比点 | React 事件机制 | JS 原生事件机制 |
---|---|---|
事件绑定 | 绑定在顶层,通过合成事件委托处理 | 直接绑定在具体的 DOM 元素上 |
事件模型 | 虚拟 DOM 层的事件冒泡 | 捕获、目标、冒泡阶段 |
事件对象 | SyntheticEvent (封装,跨浏览器兼容) |
原生 Event 对象 |
事件解绑 | 自动清理,无需手动解绑 | 需手动移除事件监听器 |
事件委托 | 默认内置,通过顶层事件委托 | 需手动实现 |
性能优化 | 内置优化,通过委托减少绑定数量 | 性能依赖开发者手动优化 |
问题4
请说说React hooks解决了什么问题? 函数组件与类组件的区别
回答:
React Hooks 解决的问题
- 状态管理:在函数组件中引入
useState
,无需类组件也能管理状态。 - 副作用处理:通过
useEffect
统一处理生命周期逻辑,避免类组件中复杂的生命周期方法。 - 代码复用:自定义 Hook 提供更清晰的逻辑复用方式,代替高阶组件 (HOC) 和 render props。
- 简化代码:减少类组件中的模板代码,提升开发效率。
函数组件与类组件的区别
- 写法:
- 函数组件是无状态组件,直到引入 Hooks 才支持状态管理。
- 类组件通过
class
声明,依赖this
来管理状态和生命周期。
- 状态和生命周期:
- 函数组件用
useState
和useEffect
管理状态和副作用。 - 类组件用
state
和生命周期方法。
- 函数组件用
- 性能:
- 函数组件更轻量,性能更优