React JS 面试题及答案精选(2026)
准备参加 React JS 面试?是时候了解一下面试内容了。 React JS面试题 有助于展现你的概念清晰度和实际执行能力。
React JS 为拥有技术经验和领域专长的专业人士提供了巨大的职业发展机会。无论您是应届毕业生还是拥有 5 年或 10 年专业经验的资深人士,分析能力和技术专长都至关重要。这些问答可以帮助团队领导、经理和开发人员提升技能,并在高阶面试中脱颖而出。
这份汇编基于 85 多位专业人士(包括招聘经理和技术领导者)的见解,反映了来自各个领域工作团队的各种行业期望和真实的面试模式。

React JS 面试题及答案
1)解释虚拟 DOM 以及 React 中的协调机制。
答:
虚拟 DOM 是 React 维护的 UI 的内存表示,用于高效地计算 UI 变化。当状态或属性发生变化时,React 会渲染一个新的虚拟 DOM 树,然后运行一个更新。 差异 使用算法对之前的树进行分析,以发现所需的最小实际 DOM 操作集。这个过程称为 和解最大限度地减少布局抖动和代价高昂的浏览器重排。React 赋值 键 它会检查列表中的元素,以帮助其在不同渲染场景下匹配节点,并使用启发式方法(例如比较类型和键)来决定是否更新、重新排序或删除节点。这样做的好处包括更新可预测、bug 发生的可能性更小,以及在复杂 UI 中表现更佳。
计费示例:
渲染动态聊天消息列表:通过使用稳定的 key 值(消息 ID),只有新消息才会添加到 DOM 中,而现有节点保持不变,从而避免不必要的重新渲染。
2) React 中组件生命周期有哪些不同类型,Hooks 如何与它们对应?
答:
React 组件会经历挂载、更新和卸载三个阶段。在类组件中,生命周期方法(例如: componentDidMount, shouldComponentUpdate, componentDidUpdate和 componentWillUnmount 控制副作用、渲染决策和清理工作。在函数组件中, 钩 提供同等能力: useEffect 处理渲染后的效果;内部包含清理函数。 useEffect 卸载时或下一个效果出现之前运行; useMemo 和 useCallback 控制记忆化;以及 useRef Hooks 能够跨渲染持久化可变引用。它的优势包括可组合性、更少的“this”绑定问题以及通过自定义 Hooks 更轻松地重用逻辑,而主要缺点是需要学习 Hooks 的规则和依赖管理。
请举例说明:
- 安装效果:
useEffect(() => fetchData(), []). - 卸载时进行清理:
useEffect(() => { start(); return stop; }, []).
3) 对于 React 应用程序,如何决定使用客户端渲染 (CSR)、服务器端渲染 (SSR)、静态站点生成 (SSG) 还是增量静态重生成 (ISR)?
答:
渲染策略应由用户体验需求、数据新鲜度、SEO需求、基础设施限制和开发速度驱动。 企业社会责任 适用于需要身份验证且SEO次要的交互式应用程序。 SSR 为公共页面提供真实数据的首次绘制,从而改善首次加载时间和 SEO,但服务器成本更高。 SSG 在构建时预先计算页面,以实现极佳的速度和缓存,尤其是在数据更改不频繁的情况下。 ISR 静态页面按需增量更新,兼顾新鲜度和性能。影响因素包括缓存性、个性化、面向全球用户的延迟以及操作复杂性。
表格:优点与缺点
| 途径 | 优势 | 缺点 |
|---|---|---|
| 企业社会责任 | 简单的托管,丰富的互动性 | 首屏速度慢,SEO效果差 |
| SSR | 出色的SEO,首次加载时数据新鲜。 | 服务器负载更高,复杂性更高 |
| SSG | 快速、便宜、对 CDN 友好 | 内容过期,直到重建完成 |
| ISR | 快速且保鲜 | 需要管理的环节更多 |
4) 应该使用哪种状态管理策略:本地状态、Context、Redux 还是查询库?
答:
选择 最简单的工具 它处理问题的特性。组件局部状态通过 useState or useReducer 非常适合处理孤立的 UI 问题。 语境 适用于读取较多的应用程序范围值(主题、语言环境、当前用户),但未针对大型树的高频更新进行优化。 终极版 或者类似的事件溯源存储,在需要可预测性、时间旅行调试、中间件和严格的单向数据流时表现出色。 数据获取库 (例如,React Query 风格的模式)管理服务器状态生命周期——缓存、去重ping重新获取策略和同步——减少样板代码。务实的架构经常使用 本地状态 + 配置上下文 + 服务器状态库,将 Redux 保留用于复杂的工作流程。
计费示例:
仪表盘使用 React Query 进行 API 缓存,使用 Context 进行主题设置, useReducer 在用于本地事件处理的复杂控件内部。
5) useEffect 和 useLayoutEffect 有什么区别?它们分别适用于什么情况?
答:
useEffect 该函数在浏览器完成渲染后运行,因此适用于数据获取、订阅和日志记录等非阻塞任务。 useLayoutEffect 执行 在 DOM 变更之后、绘制之前同步进行允许进行测量和布局调整,这些调整必须在无闪烁的情况下进行(例如,读取元素尺寸并同步重新应用样式)。缺点是 useLayoutEffect 过度使用会导致阻碍绘画并损害响应速度。一个好的原则是:从……开始 useEffect 副作用及寻求帮助 useLayoutEffect 仅当必须测量或同步修改布局以确保视觉正确性时才需要这样做。
请举例说明:
useEffect渲染完成后获取用户个人资料。useLayoutEffect:在绘制之前测量工具提示的大小以定位它。
快速比较
| 特点 | 使用效果 | useLayoutEffect |
|---|---|---|
| 定时 | 画完之后 | 油漆前 |
| 用例 | 数据、订阅 | 测量,同步布局修复 |
| 风险 | 如果负载较高,可能会出现轻微卡顿。 | 如果油漆很重,就用油漆块涂漆。 |
6) 解释列表中的键是如何工作的,以及使用数组索引的陷阱。
答:
键使 React 能够进行数据协调,从而在渲染之间准确识别列表项。稳定且唯一的键允许 React 以最小的 DOM 变更来重新排序、插入或删除项目。 数组索引 当列表项可以重新排序、插入或删除时,使用索引作为键会存在问题,因为 React 可能会将之前的状态与错误的元素关联起来,从而导致一些不易察觉的错误(例如,输入值或动画错误)。最佳实践是使用不可变的、特定于领域的标识符,例如数据库 ID。如果列表是完全静态的且永远不会重新排序,则可以使用索引,但这只是例外情况,而非普遍做法。
计费示例:
可拖动的看板应该使用卡片 ID,而不是索引,以便在拖放过程中保持组件的身份。
7) 在 React 中,记忆化技术适用于哪些场景?它们的优点和缺点是什么?
答:
记忆化通过在输入未发生变化时重用先前的结果来减少不必要的计算和重新渲染。在 React 中, React.memo 缓存组件输出, useMemo 缓存耗时的计算,以及 useCallback 它会将传递给子函数的函数标识进行记忆化。其主要优点是性能稳定,并且在高交互环境下能降低 CPU 使用率。缺点包括复杂性、依赖关系错误时可能出现缓存失效错误以及内存开销。
表格:不同的记忆方法
| 类型 | 目的 | 需要考虑的典型因素 |
|---|---|---|
React.memo(Component) |
如果 props 浅相等,则跳过重新渲染。 | 道具波动率,儿童成本 |
useMemo(fn, deps) |
缓存计算值 | 计算成本与内存成本 |
useCallback(fn, deps) |
稳定函数恒等式 | 依赖关系正确性 |
请举例说明:
使用以下方式将已过滤、已排序的数据集缓存到网格中 useMemo并用 React.memo 避免重新渲染导致的崩溃。
8)您更喜欢表单中的受控组件还是非受控组件?请讨论其优点、缺点以及表单状态的类型。
答:
受控组件 通过绑定输入到 React 状态 value 和 onChange这使得验证、掩码和条件式 UI 能够基于单一数据源实现。其优点是可预测性强,易于与其他状态集成;缺点是每次按键都需要重新渲染,除非进行优化。 不受控组件 依赖 DOM 作为数据源,并使用 refs 进行引用,这种方式开销更低,基本表单的连接也更简单,但验证机制不够集中。对于复杂的流程,混合模式很常见:关键字段使用受控输入,而大段文本区域则使用非受控输入。
计费示例:
注册表单使用受控字段进行电子邮件和密码验证,而备注文本区域则不受控,以减少重新渲染的开销。
9) 何时使用 Context 而不是自定义 hook,它们在概念上有什么区别?
答:
语境 是一个意念波· 运输机制 对于许多组件都需要的值,避免了属性层级传递。它本身并不管理状态;它只是将状态暴露给子组件。 定制挂钩 Context 封装了可重用的逻辑——结合了状态、效果和外部服务——并返回值和函数。使用 Context 提供共享的、主要为读取的配置或暴露 store,并使用自定义钩子来实现 store 的行为或协调诸如身份验证、功能标志或数据获取策略之类的事项。两者相辅相成:一种常见的模式是 useAuth() 作为一种定制钩子,由 AuthContext.
请举例说明:
AuthProvider 通过 Context 提供用户和令牌; useAuth 处理登录、刷新和注销的副作用。
10)能否概述大型 React 应用程序的性能调优策略,包括慢渲染和生命周期热点的特征?
答:
性能调优始于测量。使用 React DevTools Profiler 和浏览器性能面板识别性能瓶颈,定位代码合并热点和开销较大的提交。策略包括: 州地方 (保持国家与其消费者之间的距离), 记忆化 (React.memo, useMemo, useCallback), 列表虚拟化 对于长长的清单, 代码拆分 采用懒加载来减少初始打包大小,并且 防抖动或节流 高频事件。对于服务器端数据,采用带有查询库的缓存机制并加以利用。 适合营造悬念 优化加载流程的模式。注意生命周期中的热点问题,例如由于依赖关系过多而导致效果运行过于频繁,或者由于上下文值频繁变化而导致组件重新渲染。
请举例说明:
使用窗口库虚拟化 10,000 行的表格;通过基于路由的代码分割延迟加载大型图表,以改善初始绘制。
11)React 中的 props 和 state 有什么区别?
答:
以上皆是 props 和 state 影响组件的渲染方式,但它们的用途和生命周期从根本上有所不同。 道具 属性(properties 的缩写)是从父组件传递给子组件的不可变输入,用于定义渲染的配置或数据。它们流式传输 向下 在 React 的单向数据流中,接收组件永远不应该修改它。 州另一方面,它是可变的,由组件内部维护。它决定了随时间变化的动态行为,例如表单输入值或切换可见性。
主要差异表:
| 因素 | 道具 | 州 |
|---|---|---|
| 可变性 | 不可变的 | 可变的 |
| 所有权 | 由父母传授 | 由组件所有 |
| 更新方式 | 父级重新渲染 | useState or setState |
| 用例 | 配置 | 动态用户界面变化 |
| 生命周期 | 在渲染期间存在 | 持久化,触发重新渲染 |
计费示例:
A <Button color="blue" /> 使用道具来决定颜色,而 clicked 该布尔值用于切换视觉反馈。
12) 解释 React 中的组件架构模式以及组件的不同分类方式。
答:
React 应用遵循以下规则 基于组件的架构将用户界面拆分成小的、可重用的构建模块。组件可以根据其特性进行分类。 目的 和 责任:
- 展示(哑)组件 – 专注于用户界面,通过 props 接收数据,很少管理状态。
- 容器(智能)组件 – 处理逻辑、获取数据和管理状态;它们渲染展示组件。
- 高阶分量(HOC) – 接受一个组件并返回具有附加行为的增强版本的函数。
- 纯组分 – 通过浅层比较 props 和 state 来优化性能。
- 功能组件与类组件 – 为了提高可读性和性能,现在更倾向于使用函数式组件(带有钩子)。
计费示例:
A <UserProfile /> 组件可能是展示性的,用于接收用户信息,而 <UserProfileContainer /> 获取数据并管理其生命周期。
13) React 如何处理错误边界,以及为什么错误边界很重要?
答:
误差边界 是特殊的 React 组件,用于捕获 Java脚本错误会在渲染、生命周期方法或构造函数期间,在其子组件树的任何位置发生。它们通过将故障隔离到特定子树来防止整个应用程序崩溃。您可以使用以下方法实现一个: componentDidCatch(error, info) 和 static getDerivedStateFromError() 在类组件中。
优点:
- 通过显示备用界面来保持界面稳定性。
- 捕获并记录错误以进行分析。
- 防止级联卸载。
计费示例:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
render() { return this.state.hasError ? <h2>Something went wrong.</h2> : this.props.children; }
}
14) 什么是 React Fragments,它们与包装器有何不同?元素?
答:
应对 片段 (<></>允许您对多个元素进行分组,而无需向 DOM 添加额外的节点。这对于更清晰的结构至关重要,尤其是在列表、表格和语义化 HTML 中,因为额外的包装器可能会导致布局或可访问性问题。与包装器不同 <div>Fragments 不会渲染到 DOM 中,因此具有性能和语义优势。
计费示例:
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
差异表:
| 因素 | Fragment | <div> 包装 |
|---|---|---|
| DOM 输出 | 没有 | 添加额外节点 |
| 用例 | 结构组ping | 样式或布局 |
| 性能 | 更好 | 轻微开销 |
15)你会使用哪个 React Hook 来进行性能优化?为什么?
答:
对性能要求较高的 React 组件通常依赖于 记忆钩子 和 延迟加载 为了最大限度地减少重复工作。常用的钩子包括:
useMemo→ 缓存计算成本高的结果。useCallback→ 防止因函数标识更改而导致不必要的子渲染。useTransition→ 推迟非紧急更新,以获得更流畅的用户界面。useDeferredValue→ 将繁重的计算延迟到立即交互之后。
计费示例:
一个使用大型数据网格 useMemo 过滤后的结果可以降低 50% 或更多的 CPU 占用率。
优点:
- 减少渲染浪费。
- 保持用户界面在高负载下响应迅速。
缺点:
- 需要精确控制依赖关系;如果管理不当,可能会出现过期缓存错误。
16)什么是 React Portal,它们有哪些优势?
答:
门户 允许 React 组件将子元素渲染到父级层级结构之外的 DOM 节点中,通常用于模态框、工具提示或下拉菜单等需要在视觉上“避开”溢出或堆叠上下文的元素。使用以下方式实现: ReactDOM.createPortal(child, container)它们保持事件冒泡的一致性,因此事件处理程序的工作方式就好像元素仍然在其原始层次结构中一样。
优势表:
| 企业优势 | 描述 |
|---|---|
| 结构独立性 | 在父树外部渲染 |
| CSS/堆叠控制 | 避免 overflow: hidden 或 z-index 问题 |
| 事件传播 | React 的合成事件仍然会正确地冒泡。 |
| 雷乌斯能力 | 非常适合全局叠加 |
计费示例:
createPortal(<ModalContent />, document.getElementById('modal-root'));
17) 解释 React Router 如何管理页面之间的导航和状态。
答:
React Router 是一个声明式路由库,它将 UI 与浏览器的 URL 同步。它使用 历史 API 无需重新加载整个页面即可操作会话历史记录。核心概念包括 路线, 链接和 插座 用于嵌套路由。该库支持 动态路线, URL参数和 导航钩子 (useNavigate, useParams, useLocationReact Router v6 引入了简化的语法和数据 API。 装载机 和 行动 功能,改进SSR集成和状态管理。
计费示例:
<Route path="/user/:id" element={<UserProfile />} />
产品优势
- 启用单页导航。
- 保持滚动位置和历史记录。
- 与懒加载完美集成,性能更佳。
18)在 React 应用程序中处理副作用有哪些不同的方法?
答:
副作用是指影响组件作用域之外的操作(例如 API 调用、DOM 操作、订阅)。主要工具包括:
useEffect用于渲染后的客户端效果。- 事件处理程序 用于用户驱动的效果。
- 自定义挂钩 重用效果逻辑(例如,
useFetch). - 中间件 (例如 Redux Saga 或 Thunk)用于复杂的异步编排。
- React 查询或SWR 用于自动管理服务器状态和重新获取生命周期。
计费示例:
A useEffect 挂载时获取一次数据:
useEffect(() => { fetchData(); }, []);
优点:
简化异步管理、更好的封装和更清晰的生命周期控制。
19)React 是一个框架还是一个库?讨论决定二者区别的因素。
答:
React 正式成为 图书馆它并非一个完整的框架,而仅仅是一个框架。它只关注…… 视图层提供渲染、状态和组件绝对值trac不强制执行路由、数据获取或构建结构。
比较表:
| 因素 | 库(React) | 框架(Angular、Vue) |
|---|---|---|
| 适用范围 | 视图渲染 | 完整的 MVC 架构 |
| 自以为是 | 低 | 高 |
| 通过积极争取让商标与其相匹配的域名优先注册来维护 | 开发者驱动 | 框架驱动 |
| 灵活性 | 高 | 受惯例限制 |
| 学习曲线 | 中 | 由于复杂性而更高 |
React 生态系统(Redux、Router、Query、Next.js)有效地构成了一个“元框架”,提供了模块化的组合性,使开发人员能够构建自己的架构。
20)何时应该使用 React.lazy 和 Suspense,它们的优势是什么?
答:
React.lazy 使 代码拆分 通过仅在需要时动态加载组件, Suspense 在组件准备就绪之前,提供一个备用用户界面。这种组合可以提高初始加载性能和用户感知到的响应速度。
计费示例:
const Chart = React.lazy(() => import('./Chart'));
<Suspense fallback={<Loader />}>
<Chart />
</Suspense>
优势表:
| 企业优势 | 说明 |
|---|---|
| 性能 | 按需加载代码 |
| 用户体验 | 优雅加载回退 |
| 捆绑尺寸 | 较小的初始捆绑包 |
| 简单 | 原生 React API,极简设置 |
最佳实践:
- 将多个惰性组件封装在一个 Suspense 边界中。
- 使用有意义的备用指示器以提高可访问性。
21) 解释 React 服务器组件 (RSC) 是什么以及它们的优势。
答:
React 服务器组件 (RSC) 是一项重大创新,它通过允许组件……来增强性能和开发者体验。 在服务器上渲染,而无需发送他们的 Java给客户的脚本它们完全在服务器上执行,安全地获取数据、从数据库读取数据或执行 I/O 操作,然后将序列化输出流式传输到客户端。
优点:
- 较小的包装尺寸 — 仅服务器端逻辑,无需客户端 JS。
- 提高性能 — 服务器端数据获取减少了瀑布流。
- 安保防护 — 敏感代码永远不会到达浏览器。
- 更好的缓存 — 服务器组件可在边缘进行缓存。
计费示例:
A <ProductList /> 服务器组件可以直接从数据库中获取数据并将结果传递给…… <ProductCard /> 客户端组件。
22) React 水合和协调之间有什么区别?
答:
虽然这两个术语都涉及 React 更新 UI,但它们的目的不同:
- 和解 是将虚拟 DOM 树与其先前版本进行比较,以确定最小 DOM 更新集的过程。
- 保湿另一方面,则是将 React 的事件监听器和内部结构附加到……的过程。 服务器端渲染的 HTML 在客户端,将静态标记转换为完全交互式的应用程序。
比较表:
| 因素 | 和解 | 保湿 |
|---|---|---|
| 触发端口 | 客户端重新渲染 | 初始页面加载(SSR) |
| 目的 | 高效更新 DOM | 使 SSR HTML 具有交互性 |
| 适用范围 | 虚拟 DOM 差异 | 事件绑定 + 状态重附 |
| 频率 | 多次 | SSR渲染之后 |
计费示例:
Next.js 应用发送预渲染的 HTML 后,React 水合物 这样,组件就可以响应事件而无需重新渲染所有内容。
23) 在 React 18+ 中,并发渲染如何改善用户体验?
答:
并发渲染允许 React 根据用户优先级中断、暂停或恢复渲染工作。这可以防止 UI 在繁重的计算或重新渲染期间卡顿。诸如此类的功能包括: useTransition 和 useDeferredValue 利用这种能力进行分离 紧急更新 (比如 ty)ping) 从 非紧急 例如过滤之类的。
产品优势
- 流畅、响应迅速的交互体验。
- 采用时间切片技术防止阻塞主线程。
- 可预测的优先级排序,带来更好的用户体验。
计费示例:
const [isPending, startTransition] = useTransition(); startTransition(() => setFilteredList(filter(items, term)));
给你,typing 即使在筛选大型数据集时,React 也能保持流畅,因为它会同时安排非紧急更新。
24)在 React 应用程序中执行测试有哪些不同的方法?
答:
React 测试可以分为以下几类: 单元, 积分和 端至端 水平。
测试方法表:
| 类型 | 工具 | 目的 |
|---|---|---|
| 单位 | 有 | 测试独立功能/组件 |
| 之路 | 反应测试库 | 测试用户界面交互和状态变化 |
| E2E | Cypress 剧作家 | 在真实浏览器中测试用户流程 |
最佳实践:
- 比较喜欢 反应测试库 酶(现代的、面向DOM的)。
- 使用模拟 API
msw(模拟服务人员) - 避免测试实现细节——重点关注行为。
计费示例:
test('renders user name', () => {
render(<User name="Alice" />);
expect(screen.getByText(/Alice/)).toBeInTheDocument();
});
25) React 最常用的构建工具和打包工具有哪些?它们之间有什么区别?
答:
React 可以与多种打包工具和编译器集成,每种工具和编译器都针对不同的使用场景进行了优化。
比较表:
| 工具 | 特征: | 优势 | 缺点 |
|---|---|---|---|
| 的WebPack | 高度可配置 | 成熟且插件丰富 | 复杂的设置 |
| 螺丝钉 | 基于 ESM 的极速开发服务器 | 即时 HMR,现代语法 | 有限的旧版插件支持 |
| 包 | 零配置 | 自动优化 | Less 柔软 |
| 编译器 | 基于 Go 的编译器 | 极快 | 生态系统插件数量减少 |
计费示例:
现代项目通常采用 螺丝钉 为了开发速度和 编译器 在 CI/CD 流水线中实现高效的生产构建。
26)Next.js 如何扩展 React 的功能?
答:
Next.js 是一个 反应框架 它为路由、服务器端渲染 (SSR) 和静态图像生成提供预设架构。它引入了混合渲染模型、API 路由和边缘部署功能。
优点:
- 内建的 SSR/SSG/ISR 支持。
- 应用路由器 使用 React 服务器组件。
- 图像优化 和 中间件 为了性能和安全性。
- 简易的无服务器函数API路由。
计费示例:
app/page.js 适用于 SSR 渲染的页面; app/api/route.js 适用于服务器端点。
综上所述Next.js 能够以最少的配置实现生产级 React 应用。
27) React 中常见的性能陷阱有哪些?如何避免这些陷阱?
答:
React 性能优化中常见的陷阱包括:
- 不必要的重新渲染 — 修复使用
React.memo或者拆分组件。 - 内联对象/数组创建 - 用
useMemo用于稳定参考。 - 大列表 — 实现窗口(
react-window,react-virtualized). - 大量计算 — 缓存或卸载到 Web Worker。
- 过度使用语境 — 频繁的更新会深入传播;更倾向于派生状态。
计费示例:
如果你通过 { a: 1 } 如果该组件是内联的,并且已启用记忆化,则每次父组件渲染时它都会重新渲染。解决方法是将该对象也启用记忆化。
性能提示表:
| 问题 | 优化技术 |
|---|---|
| 重新渲染 | React.memo, useCallback |
| 昂贵的计算 | useMemoWeb Workers |
| 大型数据集 | 虚拟化 |
| 频繁的上下文更新 | 本地化状态 |
28) 解释 useReducer 和 useState 之间的区别。
答:
这两个钩子都能管理状态,但它们在复杂性和控制方面有所不同。
useState非常适合简单、孤立的状态转换。useReducer将复杂的状态逻辑集中到一个 reducer 函数使用dispatch可预测更新的操作。
比较表:
| 因素 | 使用状态 | 使用减速器 |
|---|---|---|
| 句法 | [value, setValue] |
[state, dispatch] |
| 复杂 | 简易 | 中等至复杂 |
| 用例 | 独立国家 | 相关或嵌套状态 |
| 调试 | Less 详细 | 通过记录操作可以更轻松地完成操作 |
| 例如: | 表单切换 | 表单验证或多步骤表单 |
计费示例:
const [state, dispatch] = useReducer(reducer, { count: 0 });
dispatch({ type: 'increment' });
29) 如何提高 React 应用程序中的可访问性 (a11y)?
答:
无障碍设计确保所有用户,包括残障人士,都能有效使用您的应用。React 通过语义标记和 ARIA 属性来增强无障碍功能。
最佳实践:
- 绝大部分储备使用 语义HTML (
<button>vs<div onClick>). - 使用以下方式管理注意力
ref和tabIndex. - 使用 ARIA 角色来管理动态组件。
- 确保图像的颜色对比度和文字替代。
- 利用类似的工具 Eslint-Plugin-JSX-A11Y 和 斧芯 进行审计。
计费示例:
<button aria-label="Close dialog" onClick={closeModal}>×</button>
优点:
- 覆盖更广泛的受众。
- 搜索引擎优化。
- 符合 WCAG 标准。
30)你能描述一下代码分割和延迟加载的区别,以及何时使用哪一种吗?
答:
这两种技术都能优化数据包大小和负载性能,但它们的区别在于: 执行时间.
- Code 分裂 将大型软件包分割成可以独立加载的较小块。
- 懒加载 延迟加载这些数据块,直到需要它们时才加载。
比较表:
| 因素 | Code 拆分 | 延迟加载 |
|---|---|---|
| 定义 | 将代码分成多个块 | 按需加载数据块 |
| 工具 | Webpack、Vite | React.lazy, 动态的 import() |
| 目的 | 优化捆绑包大小 | 提高运行时性能 |
| 执行 | 构建时间 | 运行时 |
计费示例:
const Settings = React.lazy(() => import('./Settings'));
这些技术结合起来,可以缩短交互时间,提高大型应用程序的感知速度。
31) 解释渲染属性的概念,以及它与高阶组件 (HOC) 的区别。
答:
渲染属性 是 React 中的一种模式,其中组件接受一个参数。 作为属性 它告诉系统要渲染什么内容。这样就可以在多个组件之间共享组件逻辑,而无需重复编写代码。
另一方面,HOCs 包装 创建一个组件并返回一个增强版本,其中注入了属性或行为。
比较表:
| 因素 | 渲染属性 | HOC |
|---|---|---|
| 技术实施 | 扮演子角色 | 函数包装ping 元件 |
| 组成成分 | 内联控制 | 声明式包装ping |
| 可读性 | 通常更清晰 | 可能导致包装器地狱 |
| 用例 | 动态渲染逻辑 | 跨领域关注点 |
计费示例:
<DataProvider render={data => <UserList users={data} />} />
渲染属性提供了更好的灵活性,并避免了高阶组件中常见的名称冲突。
32)定制鱼钩有哪些不同类型及其优点?
答:
自定义钩子封装了可重用的逻辑,结合了状态、副作用和实用工具。它们提高了代码的可重用性、关注点分离性和可测试性。
类型及示例:
- 状态管理钩子 –
useToggle,useForm. - 数据获取钩子 –
useFetch,useQuery. - UI/UX钩子 –
useWindowSize,useDarkMode. - 集成钩子 –
useLocalStorage,useMediaQuery. - 表演钩子 –
useDebounce,useThrottle.
优点:
- 集中式逻辑重用。
- 更清洁的部件。
- 独立测试。
计费示例:
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => JSON.parse(localStorage.getItem(key)) || initial);
useEffect(() => localStorage.setItem(key, JSON.stringify(value)), [value]);
return [value, setValue];
}
33)如何处理 React 应用程序中的内存泄漏?
答:
内存泄漏是指已卸载的组件仍然持有对资源或订阅的引用。这会降低性能并导致不可预测的行为。
预防技术:
- 清理效果 in
useEffect: useEffect(() => { const id = setInterval(logData, 1000); return () => clearInterval(id); }, []); - 中止异步调用 使用
AbortController. - 避免保留过期的瓶盖 引用旧的 props/state。
- 取消订阅事件或套接字 卸载时。
- 使用 React Profiler 用于检测记忆增长缓慢。
计费示例:
在聊天应用中,当用户离开聊天室时,务必断开套接字监听器。
34) 在大型 React 应用程序中管理表单的最佳实践是什么?
答:
在企业级 React 应用中管理表单需要在控制、性能和可维护性之间取得平衡。
最佳实践:
- 使用类似的库 福米克, 反应钩形 或 最终形式 用于验证和字段注册。
- 使用嵌套组件或上下文对相关字段进行分组。
- 在断裂前, 架构验证 (没错,佐德)为了保持一致性。
- 对繁重的验证或 API 检查进行防抖处理。
- 除非需要全局保存,否则请保持表单状态本地化。
计费示例:
React Hook Form 通过隔离输入状态来最大限度地减少重新渲染。
const { register, handleSubmit } = useForm();
<input {...register('email', { required: true })} />
35)在 React 开发中,哪些设计模式最有用?它们的特点是什么?
答:
React 自然而然地适用于多种软件设计模式,从而构建可维护和可扩展的 UI 架构。
| 模式 | 描述 | 例如: |
|---|---|---|
| 容器演示器 | 将逻辑(容器)与用户界面(呈现器)分离 | 数据容器 → UI组件 |
| 受控-非受控 | 通过状态而非 DOM 管理表单数据 | Formik 与原始输入 |
| 化合物成分 | 父母控制子女的创作 | <Tabs><Tab /></Tabs> |
| 提供者模式 | 通过上下文共享状态 | 主题提供商 |
| 钩针图案 | 重用有状态逻辑 | useAuth, useFetch |
计费示例:
A Tabs 组件暴露上下文 <Tab> 儿童会自动注册——一个简洁的应用程序 化合物成分 格局。
36) React 18 和 React 19 的主要区别是什么?
答:
React 19 在 React 18 的并发基础上,增加了许多重要的新功能。
| 特性 | 反应18 | 反应19 |
|---|---|---|
| 并发渲染 | 介绍 | 悬念增强,效果更佳。 |
| 服务器组件 | 实验 | 稳定且集成 |
| 操作API | 不可用 | 处理表单操作的新标准 |
| 资源加载 | 用户手册 | 自动资源加载 |
| 改进的错误处理 | 基础版 | 带边界钩的颗粒 |
主要优点:
React 19 的重点是 更简单的数据突变, 内置表单操作和 增强的异步控制使 SSR 和渐进式补水更加顺畅。
37) 微前端是如何运作的 Architecture 与 React 集成有哪些优势?
答:
微前端将大型 Web 应用拆分成独立的、可部署的前端模块。在 React 生态系统中,每个微前端都是一个独立的应用程序,可以通过以下方式集成: 模块联盟, I帧 或 自定义运行时加载器.
优点:
- 独立部署和扩展。
- 跨技术栈的团队自主性。
- 更快的构建流程。
计费示例:
运用 Webpack 模块联合团队可以动态地在应用程序中公开 React 组件:
exposes: { './NavBar': './src/NavBar' }
缺点:
- 共享状态管理的复杂性。
- 隔离捆绑包带来的性能开销。
38)在生产环境中扩展 React 应用程序时,您会考虑哪些因素?
答:
扩展 React 应用程序涉及技术、架构和运维方面的考虑。
关键因素:
- Code 结构体 — 采用 monorepos(Nx/Turborepo)进行模块化代码共享。
- 状态管理 — 区分本地、全局和服务器状态。
- 性能 — 延迟加载、记忆化、CDN 缓存。
- 监控 — 使用 Sentry、Datadog 或 LogRocket 来获取错误和指标。
- 测试与持续集成/持续交付 — 自动化流程和视觉回归测试。
计费示例:
一个大型电子商务平台使用 Next.js 进行 SSR,使用 Redux Toolkit 进行可预测状态,并使用微前端来扩展 React 应用程序,以实现独立的垂直领域。
39)如何测试使用异步行为的 React 组件?
答:
测试异步 React 组件需要测试运行器和组件状态更新之间的同步。
最佳实践:
- 绝大部分储备使用
waitFororfindBy*React Testing Library 中的查询。 - 使用模拟获取调用或 API
msw. - 比较喜欢 假计时器 (
jest.useFakeTimers()) 用于基于超时的效果。
计费示例:
test('loads and displays data', async () => {
render(<UserList />);
expect(await screen.findByText('Alice')).toBeInTheDocument();
});
这样可以确保测试在进行断言之前等待 React 的异步更新。
40) 解释一下你会如何设计一个大规模、可维护的 React 项目结构。
答:
一个可扩展的 React 项目必须在模块化、清晰度和团队协作之间取得平衡。
推荐的文件夹结构:
src/ ├── components/ # Reusable UI elements ├── features/ # Feature-specific modules ├── hooks/ # Custom reusable hooks ├── context/ # Global providers ├── pages/ # Route-level views ├── services/ # API and utilities ├── assets/ # Static resources ├── tests/ # Unit & integration tests └── index.js
最佳实践:
- 使用路径别名进行绝对导入。
- 严格执行代码检查(ESLint + Prettier)。
- 绝大部分储备使用 TypeScript 为了型式安全。
- 通过原子设计或基于特征的切片来强制执行组件边界。
计费示例:
在实际应用中,“用户”功能可能包括 UserSlice.js, UserAPI.js, UserCard.jsx和 User.test.js, 全部在 src/features/user/.
🔍 React.js 热门面试题及真实案例分析和策略性回答
1)React.js 中的函数式组件和类组件有哪些主要区别?
对候选人的期望: 面试官想考察你对 React 组件架构和现代最佳实践的理解。
示例答案:
函数式组件更简单,依靠钩子来管理状态和生命周期方法,而类组件则使用 this 以及生命周期方法,例如 componentDidMount如今,函数式组件普遍受到青睐,因为它们能编写更简洁的代码,更容易测试,并且由于 React 渲染过程的优化,性能也更好。
2)你能解释一下 React 中的虚拟 DOM 是如何工作的吗?
对候选人的期望: 面试官想评估你对 React 核心性能机制的掌握程度。
示例答案:
“虚拟 DOM 是真实 DOM 的内存表示。当组件状态发生变化时,React 首先更新虚拟 DOM,然后使用称为‘差异比较’的过程将其与之前的版本进行比较,最后仅更新真实 DOM 中发生变化的部分。这种方法通过最大限度地减少直接的 DOM 操作来提高性能。”
3)如何在大型 React 应用程序中管理状态?
对候选人的期望: 面试官想了解您在状态管理技术和工具方面的经验。
示例答案:
“在大型应用中,我通常使用集中式状态管理库,例如 Redux 或 Zustand。Redux 提供可预测的数据流,并通过时间旅行调试工具简化调试过程。对于更简单的应用,我更喜欢使用 Context API 和 hooks,以避免不必要的复杂性。”
4)描述一下你优化 React 性能的一次经历。
对候选人的期望: 面试官想了解你在性能优化方面的实践经验。
示例答案:
“在我之前的职位上,我们的应用程序由于不必要的状态更改而过度重新渲染。我使用 React.memo 和 useCallback 我添加了一个钩子来防止不必要的重新渲染。我还使用 React Profiler 分析了性能,并确定了需要缓存的组件,这使渲染时间减少了近 30%。
5)在 React 中如何处理副作用?
对候选人的期望: 面试官想评估你对钩子和生命周期管理的理解。
示例答案:
我使用以下方式处理副作用,例如 API 调用或 DOM 操作: useEffect 钩子。钩子允许我指定依赖项,确保效果仅在这些依赖项发生变化时运行。这有助于保持可预测的行为并避免无限循环。
6)请告诉我你在 React 项目中遇到的一个具有挑战性的 bug,以及你是如何解决的。
对候选人的期望: 面试官想评估你的问题解决能力和调试能力。
示例答案:
“在之前的职位上,我遇到过一个bug,状态更新没有反映在用户界面上。经过调查,我发现问题在于直接修改了状态对象,而不是创建新的副本。我重构了代码,使用不可变更新,解决了这个问题,并提高了数据一致性。”
7) 在 React 应用中如何处理表单验证?
对候选人的期望: 面试官想看看你是否了解如何实现用户输入验证。
示例答案:
“我通常使用受控组件来管理表单输入,并结合 Formik 或 React Hook Form 等库进行验证。这些工具简化了错误处理、表单状态管理以及与 Yup 等第三方验证库的集成。”
8) 描述一下你在开发 React 项目时需要与后端开发人员合作的情况。
对候选人的期望: 面试官想评估你的团队合作和沟通能力。
示例答案:
“在上一份工作中,我与后端开发人员紧密合作,为仪表盘应用程序设计 REST API。我们在开发初期就确定了数据格式和接口。我还创建了模拟响应,以便在后端构建期间继续进行前端开发,确保后续的顺利集成。”
9) 如何确保你的 React 组件可重用且易于维护?
对候选人的期望: 面试官想了解你对组件设计和可扩展性的看法。
示例答案:
“我遵循构建小型、功能单一的组件的原则。我还使用 props 来提高灵活性,并使用 CSS-in-JS 或 styled-components 等模块化框架来实现样式。这确保了组件在整个项目中可以轻松重用和维护。”
10)您如何了解 React.js 的发展趋势和最佳实践?
对候选人的期望: 面试官想评估你对持续学习的投入程度。
示例答案:
“我通过关注 React 的官方文档和社区博客来了解最新动态。我还会观看 React 大会(例如 React Conf)的演讲,并收听像‘React Podcast’这样的播客。这些资源帮助我及时了解并发渲染和服务组件等新特性。”
