React 面试题
React 面试考察你对组件模型、Hooks、渲染行为和性能的理解。预计会有概念题和短小的现场编码任务。
React 面试涵盖内容
Hooks 与状态
useState、useEffect、useMemo/useCallback、自定义 Hooks 以及 Hooks 规则。
渲染与协调
React 如何重新渲染、key、虚拟 DOM 以及避免不必要的渲染。
状态管理
本地状态与提升状态、Context,以及何时使用 Redux、Zustand 或 React Query。
性能
记忆化、代码分割、懒加载以及分析慢组件。
React 面试题示例
- React Hooks 解决了什么问题?Hooks 的规则有哪些?好回答应覆盖
- 组件逻辑复用困难与类组件复杂性
- 函数组件无状态与生命周期问题
- 规则:顶层调用、仅在函数组件或自定义Hook中调用
- 规则:条件、循环、嵌套中禁止调用
查看范例答案
React Hooks 主要解决了类组件中复杂的状态逻辑复用困难、生命周期方法逻辑分散、this 绑定容易出错等问题。Hooks 允许在函数组件中使用状态和副作用,使得逻辑复用通过自定义 Hook 更简洁,且避免了高阶组件和 render props 的嵌套地狱。Hooks 的使用必须遵循两条核心规则:一是只在最顶层调用 Hooks,不要在循环、条件或嵌套函数中调用,以保证每次渲染时 Hooks 的调用顺序一致;二是只在 React 函数组件或自定义 Hook 中调用 Hooks,不能在普通 JavaScript 函数中调用。违反这些规则会导致状态混乱和难以调试的 bug。一个常见陷阱是开发者因为条件渲染而将 Hook 放在 if 块内,这会导致调用顺序不稳。
- 解释 useMemo 和 useCallback 的区别,以及各自何时值得使用。好回答应覆盖
- useMemo缓存计算结果 vs useCallback缓存函数引用
- 依赖数组决定何时重新计算
- useMemo用于避免昂贵计算重复执行
- useCallback用于避免子组件因引用变化而重复渲染
查看范例答案
useMemo 和 useCallback 都是 React 的性能优化 Hook。useMemo 返回一个记忆化的值,当依赖数组中的值发生变化时才会重新计算,否则直接返回缓存结果,适用于避免每次渲染都执行昂贵的计算,例如复杂的数据转换或排序。useCallback 则返回一个记忆化的函数引用,只有当依赖变化时才会返回新的函数,常用于将回调函数传递给经过 React.memo 优化的子组件,以避免子组件因父组件重新渲染而接收新函数引用导致不必要的重渲染。二者都接受依赖数组作为第二个参数。使用场景:当计算量很大(如 O(n^2) 以上)且依赖不频繁变化时使用 useMemo;当子组件依赖回调函数的引用相等性时使用 useCallback。注意不要滥用,因为记忆化本身也有开销。对于轻量计算或每次依赖都变的情况,直接用普通值或函数即可。
- 什么会导致组件重新渲染?如何避免不必要的重新渲染?好回答应覆盖
- props/state变化、父组件重渲染、context值变化
- shouldComponentUpdate、React.memo 阻止重渲染
- 使用 useCallback/useMemo 稳定引用
- key 属性强制重新创建组件
查看范例答案
组件重新渲染的触发条件主要有:1) 组件自身的 state 或 props 发生变化;2) 父组件重新渲染导致子组件也跟着重渲染(即使 props 没变);3) 组件所消费的 context 值发生变化;4) 使用了 forceUpdate。避免不必要渲染的方法:使用 React.memo 包裹纯展示组件,它会浅比较 props 来决定是否重渲染;在类组件中实现 shouldComponentUpdate 或在函数组件中使用 React.PureComponent;使用 useCallback 和 useMemo 避免因引用变化导致的子组件重渲染;合理设计组件树,将易变状态下推到更深的子组件以减少影响范围;避免在渲染函数中创建新的对象或函数作为 props。常见陷阱是认为 React.memo 能阻止所有重渲染,实际上它只做浅比较,若 props 中包含对象或函数且每次渲染都新建引用,则仍然会重渲染。
- key 属性在列表中是如何工作的?为什么它很重要?好回答应覆盖
- key帮助React识别元素变化
- diff算法中通过key复用DOM节点
- 使用稳定唯一标识如id,避免索引
- key变化导致组件卸载重建
查看范例答案
key 属性是 React 列表渲染中的特殊属性,用于帮助 React 识别哪些元素被修改、添加或删除。在 Diff 算法中,React 通过比较新旧虚拟 DOM 树的 key 值来判断节点是否可复用。如果 key 相同且类型相同,React 会复用该节点并仅更新变化的 props;若 key 不同或类型不同,则直接销毁旧节点并创建新节点。因此 key 应该是稳定、唯一且可预测的,通常使用数据中的唯一 ID(如数据库 id),而不是数组索引。使用索引作为 key 在列表顺序不变时没问题,但若列表被重新排序(如插入、删除、排序),会导致性能下降甚至状态错乱(因为索引相同但元素不同)。正确使用 key 可以提升渲染性能和避免意外 bug。一个常见错误是在多个兄弟元素中使用相同的 key,这会导致 React 报错或行为异常。
- 用自定义 Hook 构建一个防抖搜索输入框。好回答应覆盖
- 自定义Hook封装防抖逻辑与API调用
- useRef保存定时器ID与最新值
- useCallback稳定防抖函数
- 清理定时器避免内存泄漏
查看范例答案
这个自定义 Hook useDebounce 接受一个值和延迟时间,返回防抖后的值。内部使用 useState 存储防抖值,并在 useEffect 中利用 setTimeout 延迟更新,同时清理前一个定时器以避免重复调用。在搜索组件中,将输入框的值通过 useDebounce 处理,然后监听 debouncedQuery 的变化来触发 API 请求。这样用户快速输入时,只有最后一次输入后的 300ms 才会执行搜索,减少了请求频率。常见的陷阱是忘记在 useEffect 的清理函数中清除定时器,导致组件卸载后仍有回调执行,造成内存泄漏或状态更新到已卸载组件。此外,如果需要在防抖期间取消上一次请求,还应使用 AbortController 或类似机制。
参考代码typescript import { useState, useEffect, useCallback, useRef } from 'react'; function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const timer = setTimeout(() => setDebouncedValue(value), delay); return () => clearTimeout(timer); // 清理定时器 }, [value, delay]); return debouncedValue; } export default function DebouncedSearchInput() { const [query, setQuery] = useState(''); const debouncedQuery = useDebounce(query, 300); // 防抖延迟300ms useEffect(() => { if (debouncedQuery) { // 调用搜索API fetchSearch(debouncedQuery); } }, [debouncedQuery]); return ( <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="输入搜索关键词..." /> ); } // 模拟搜索函数 async function fetchSearch(query: string) { console.log('搜索:', query); // 实际调用 API } - 什么情况下你会使用 Context 而不是 Redux 或 React Query 这样的状态库?好回答应覆盖
- Context用于轻量共享全局数据
- Redux适合复杂状态逻辑和中间件
- React Query专为服务端状态缓存
- Context不触发重新渲染优化差
查看范例答案
Context 适用于简单的全局数据共享,如主题、语言偏好、用户认证状态等,且这些数据更新频率低。Redux 适用于复杂的状态管理需求,如跨组件复杂交互、需要中间件处理异步逻辑、需要时间旅行调试等。React Query 则专门用于管理服务端状态(如 API 数据),提供缓存、后台刷新、同步、乐观更新等功能。选择 Context 而非 Redux 的情况:当应用中只需要少数几个全局值,且更新不频繁,组件树不深时,使用 Context 更轻量,无需引入额外的库和样板代码。Context 的缺点是当 context 值变化时,所有消费该 context 的组件都会重新渲染,即使它们只关心部分值,并且不能很好地支持细粒度订阅。Redux 和 React Query 提供了更细粒度的订阅和优化。一个常见误判是认为 Context 可以完全替代状态库,但实际上 Context 不是状态管理工具,它只是传递数据的通道。对于复杂应用,建议 Context 与 useReducer 结合处理简单状态,而对复杂异步数据流使用专门的库。
如何准备
- 能够大声解释渲染过程——面试官更关心你的思维模型,而非死记硬背的 API。
- 练习小型现场编码任务(计数器、防抖输入、获取并显示列表),直到得心应手。
- 了解每种状态工具的权衡,而不是默认选择某一种。
- 讨论优化时提及性能工具(React DevTools Profiler)。
常见问题
React 面试题主要是理论还是编码?
两者都有。会有关于 Hooks 和渲染的概念题,以及构建小组件的简短现场编码任务。
React 面试需要了解 Redux 吗?
了解其权衡以及状态库何时有帮助,但许多团队现在更喜欢 Context + React Query。理解原因比死记一个库更重要。
对 TypeScript 的掌握程度有什么要求?
大多数 React 岗位要求能熟练地为 props、state 和 hooks 添加类型。除非是高级/基础设施岗位,否则很少需要深入泛型。
如何练习 React 面试?
进行限时现场编码任务,并大声解释你的思路。Offersly 会根据你的简历生成 React 相关题目,并对你的回答评分。
练习 React 题目,即时获取 AI 反馈
上传简历,获得个性化模拟面试,并了解需要改进的地方——免费开始。