React 面试高频问题
核心概念
什么是 React?
- 用于构建用户界面的 JavaScript 库。
- 核心:组件化、虚拟 DOM、JSX、单向数据流、声明式编程。
React 的主要特性?
- 组件化、虚拟 DOM、JSX、单向数据流、声明式编程。
JSX 的作用和好处?
- JavaScript XML,在 JavaScript 中编写类似 HTML 的结构。
- 好处:易读、易写、更接近 HTML、可以使用 JavaScript 全部能力。
什么是虚拟 DOM?作用是什么?
- 对实际 DOM 的轻量级 JavaScript 对象表示。
- 作用:提高 UI 更新效率,批量更新 DOM,减少 DOM 操作次数。
React 的单向数据流是什么?
- 数据从父组件流向子组件,子组件通过 props 接收,无法直接修改。
- 子组件通过回调函数与父组件通信。
React 组件的类型?
- 函数组件: 使用函数定义,更简洁,常用 Hook.
- 类组件: 拥有状态和生命周期方法,常用。
Props 和 State 的区别?
- Props: 父组件传递给子组件的只读输入。
- State: 组件内部可变的数据,由组件自身管理,改变会触发重新渲染。
- 区别: Props外部传入,State组件内部;Props只读,State可变。
常用 React Hooks?
useState,useEffect,useContext,useReducer,useCallback,useMemo,useRef。
useEffect的作用?与componentDidMount,componentDidUpdate的关系?- 作用: 处理副作用(数据获取、订阅、手动修改 DOM 等)。
- 关系: 可以替代
componentDidMount,componentDidUpdate, 和componentWillUnmount。通过依赖数组控制执行时机。
什么是 Context?作用?
- 在组件树中传递数据,避免逐层传递 props。
- 作用:简化组件间通信,共享全局数据 (例如用户身份验证信息、主题设置)。
React 中如何处理事件?
- 小驼峰命名(如
onClick,onChange)。 - 事件处理函数作为 JSX 属性的值。
- 事件处理函数接收事件对象 (Event Object) 作为参数。
- React 默认阻止事件冒泡。
- 小驼峰命名(如
React 组件通信的几种方式?
- Props、Context、状态管理库(Redux, MobX, Zustand 等)、回调函数、事件发布/订阅、
useRef(较少)。
- Props、Context、状态管理库(Redux, MobX, Zustand 等)、回调函数、事件发布/订阅、
组件 & JSX
受控组件和非受控组件?
- 受控组件: 状态由 React state 控制 (例如,
onChange更新值)。 - 非受控组件: 状态由 DOM 本身控制 (例如,使用
ref获取值)。
- 受控组件: 状态由 React state 控制 (例如,
React 中处理表单的两种方式?
- 受控组件: 使用
onChange事件处理程序和 state 控制。 - 非受控组件: 使用
ref获取表单元素的值。
- 受控组件: 使用
JSX 中
key属性的作用?- 帮助 React 识别哪些元素发生变化、被添加或被移除。
key在map循环中必须唯一。- 提高 React 的性能。
React 中如何进行条件渲染?
if/else语句。- 三元运算符 (
? :)。 - 逻辑与运算符 (
&&)。
如何使用
Fragment? 为什么使用Fragment?<React.Fragment>或<>。- 包裹多个 JSX 元素,避免添加额外 DOM 节点。
- 好处:代码更简洁,避免不必要的 DOM 节点。
什么是高阶组件 (HOC)?如何创建?
- 接收一个组件作为参数,返回一个新的组件的函数。
- 创建步骤: 接收一个组件,返回一个新组件,在新组件渲染传入的组件并可以传递 props。
- 用途: 代码复用、逻辑提取、属性增强。
状态管理
为什么要使用状态管理库?
- 解决复杂应用中组件间状态共享和数据流管理的问题。
- 集中管理应用状态,提供可预测的状态更新方式,方便调试和追踪。
Redux 的核心概念?
- Store, Action, Reducer, Dispatch, Selector.
Redux 的数据流?
- 用户触发 action。
- Action dispatched。
- Reducer 接收 action 和当前状态。
- Reducer 返回新的 state。
- Store 通知订阅者。
- 组件重新渲染。
Redux 中如何处理异步操作?
- 中间件 (例如
redux-thunk或redux-saga)。
- 中间件 (例如
你了解哪些状态管理库?
- Redux, MobX, Zustand, Recoil。
性能优化
React 中常用的性能优化技术?
shouldComponentUpdate(类组件) 或React.memo(函数组件)。useMemo和useCallback。- 列表优化 (使用唯一的
key)。 - 代码分割 (Code Splitting) -
React.lazy和Suspense。 - 优化图片、虚拟化、避免在
render()中进行耗时操作、使用 immutable 数据结构。
React.memo的作用? 和shouldComponentUpdate的关系?React.memo: 优化函数组件的性能,默认浅比较 props 的变化。- 关系:
React.memo是shouldComponentUpdate的函数组件版本。
如何优化列表渲染的性能?
- 使用唯一的
key。 - 避免在
render()函数中进行耗时操作。 - 虚拟化。
- 使用
React.memo优化列表项组件。
- 使用唯一的
什么是代码分割?作用?
- 将代码拆分成多个小的 bundle。
- 减少初始加载时间,按需加载代码,改善用户体验。
- 使用
React.lazy和Suspense实现。
什么是懒加载?
- 在需要的时候才加载资源 (如 JavaScript 文件、图片)。
- React.lazy 和 Suspense、图片懒加载。
其他
React 学习问答 (新手友好版)
问:你用过哪些 UI 库或组件库?感觉怎么样?
答:
UI 库就像是预先做好的乐高积木,让你不用从零开始搭建按钮、表单、弹窗这些界面元素,可以更快、更规范地开发网页。我用过几个常见的:
Material UI (MUI):
- 它是什么? 它是谷歌 Material Design 设计风格的 React 实现。很多谷歌产品(如 Gmail, Google Drive)就是这种感觉。
- 我的评价 (对新人来说):
- 优点: 非常流行,组件非常全,文档也很好,社区庞大意味着你遇到问题更容易找到答案。外观看起来很现代、专业。
- 缺点: 有时候想深度定制样式可能需要多花点功夫,因为它有自己的一套样式系统。
- 新手建议: 是个很不错的起点,因为资源多,用的人也多。
Ant Design (AntD):
- 它是什么? 另一个非常流行的库,由蚂蚁集团开发,特别适合做企业后台管理系统这类应用。它有自己独特的设计风格。
- 我的评价 (对新人来说):
- 优点: 组件极其丰富,特别是表格、表单等复杂组件功能强大。设计规范统一,很适合快速搭建信息密集的界面。
- 缺点: 定制外观可能比 MUI 稍微复杂一点点(可能需要配置主题文件)。设计风格比较“企业化”,不一定适合所有类型的网站。
- 新手建议: 如果你明确要做后台管理系统,AntD 是个很棒的选择。
Chakra UI:
- 它是什么? 一个更侧重于开发者体验和灵活性的库。它大量使用 "样式属性" (Style Props) 来让你直接在组件上写样式。
- 我的评价 (对新人来说):
- 优点: 定制非常非常方便!你可以像写行内样式一样直接改组件外观,但又比行内样式强大得多。它对无障碍访问(Accessibility)支持得特别好。文档清晰易懂。
- 缺点: 可能需要你稍微多写一点样式相关的代码(但这正是它的灵活之处)。相对前两者,可能组件种类稍微少一点点(但核心的都有)。
- 新手建议: 如果你喜欢灵活定制样式,并且想学习现代的 CSS-in-JS 方式,Chakra UI 是一个绝佳的选择,对新手非常友好。
总结: 没有绝对的好坏,看项目需求和个人喜好。新手可以都简单尝试一下它们的 "Get Started" 教程,看看哪个用起来更顺手。
问:你是怎么给 React 项目做测试的?听过哪些测试工具?
答:
给 React 项目写测试,就像是给你的代码请“质检员”,确保它们能按预期工作,减少 Bug。主要分三种类型:
- 单元测试 (Unit Testing):
- 测什么? 测试最小的代码单元,比如一个独立的函数或一个简单的 React 组件。看它在特定输入下是否返回预期的输出,或者渲染出正确的样子。
- 好比: 单独测试汽车引擎能不能启动。
- 集成测试 (Integration Testing):
- 测什么? 测试多个组件或模块组合在一起时是否能正常协作。比如,一个表单组件和一个提交按钮组件一起工作,点击按钮后数据是否正确提交。
- 好比: 测试引擎、变速箱、轮子装在一起后,车子能不能往前开。
- 端到端测试 (End-to-End / E2E Testing):
- 测什么? 模拟真实用户的使用场景,从头到尾测试整个应用流程。比如,用户打开网页 -> 登录 -> 浏览商品 -> 添加到购物车 -> 结账。通常会用自动化工具在真实浏览器里跑。
- 好比: 一个试驾员把整辆车开上路,测试加速、刹车、转向、空调等所有功能。
常见的测试框架/库:
- Jest:
- 它是什么? 一个非常流行的 JavaScript 测试框架。它提供了一整套测试需要的东西:运行测试、判断结果是否正确(断言)、模拟函数(Mocking)等。你可以用它来测任何 JS 代码,包括 React。
- 好比: 测试工厂里的测试跑道、计时器、检查清单等全套设备。
- React Testing Library (RTL):
- 它是什么? 一个专门用来测试 React 组件的库,通常和 Jest 一起使用。它的核心理念是:像用户一样去测试你的组件。它鼓励你通过用户能看到或交互的元素(比如按钮文字、输入框标签)来查找和操作组件,而不是依赖组件内部的实现细节。
- 好比: 测试说明书上写的是“找到写着‘启动’的按钮并按下”,而不是“检查引擎内部的
isRunning状态是不是true”。这是目前社区非常推荐的方式。
- Enzyme:
- 它是什么? 另一个(曾经很流行的)测试 React 组件的库。它允许你更深入地检查组件的内部状态(state)和属性(props),以及进行“浅渲染”(只渲染组件本身,不渲染子组件)。
- 好比: 允许测试员在测试时直接拆开引擎看零件。现在很多人更倾向于用 RTL,因为它更关注用户行为。
新手建议: 从学习 Jest + React Testing Library 开始,这是目前的主流组合。先尝试给你的小组件写一些简单的单元测试和集成测试。
问:你对 React 的未来发展怎么看?
答:
我觉得 React 依然会是前端领域非常重要的技术,并且它还在不断进化。对新人来说,不用担心它过时,但要保持学习的心态。有几个趋势值得关注:
- React Server Components (RSC): 这是个比较大的变化。简单说,就是未来一部分 React 组件可以直接在服务器上运行并渲染,只把结果发送给浏览器。
- 好处? 可以减少发送到浏览器的代码量,加快页面加载速度,尤其对网络不好或设备性能差的用户更友好。
- 对新人的影响? 现在还不用立刻深入掌握,但知道有这个方向,未来可能会接触到。像 Next.js 这样的框架已经在积极应用了。
- 并发 (Concurrency): React 正在变得更“聪明”,能更流畅地处理多个更新任务,即使在进行复杂的计算或数据加载时,也能保持界面不卡顿。
- 好处? 用户体验更好。
- 对新人的影响? 你写的代码可能不需要大改,但 React 底层会帮你处理得更平滑。
- 性能和开发者体验持续优化: React 团队一直在努力让 React 运行得更快,同时让开发者写代码更舒服、更高效。
总结: React 在向着更快、更强、用户体验和开发者体验更好的方向发展。作为学习者,打好基础,同时关注社区动态和官方文档,了解这些新变化就好。
问:你写 React 时遇到过什么问题?怎么解决的?
答:
写代码肯定会遇到问题,这很正常!分享几个 React 里新手常见的问题和解决思路:
问题:修改了 State,但界面没更新?
- 可能原因: 最常见的是直接修改了 State 中的对象或数组(比如
myArray.push(newItem)或myObject.key = value)。React 判断是否需要更新,通常是看 State 的引用有没有变。直接修改,引用没变,React 就“以为”没变化。 - 解决方法: 永远使用
setState函数来更新 State,并且要传入一个全新的对象或数组。- 对于数组:
setMyArray([...myArray, newItem])(使用扩展运算符创建新数组) - 对于对象:
setMyObject({...myObject, key: newValue})(使用扩展运算符创建新对象) - 这叫做“状态不可变性 (Immutability)”,是 React 的核心概念之一。
- 对于数组:
- 可能原因: 最常见的是直接修改了 State 中的对象或数组(比如
问题:
useEffect里面好像陷入了无限循环?- 可能原因:
useEffect的第二个参数是依赖数组 (dependency array)。如果这个数组没写对,或者干脆没写,useEffect可能会在每次组件渲染后都执行。如果在useEffect内部又修改了某个导致组件重新渲染的 State,就可能无限循环了。 - 解决方法:
- 仔细检查
useEffect的依赖数组。只放入那些当它们的值改变时,你才需要重新执行 Effect 的变量。 - 如果 Effect 只需要在组件第一次加载时执行一次(比如请求初始数据),传入一个空数组
[]。 - 如果忘记了某个依赖,或者加入了不必要的依赖,都可能出问题。React 官方的 linter (代码检查工具) 通常会对此给出警告。
- 仔细检查
- 可能原因:
问题:数据要一层一层传很多层组件,好麻烦 (Prop Drilling)!
- 可能原因: 应用结构比较深,顶层组件的数据要给很底层的组件用,只能通过中间的每一层组件都把 props 往下传。
- 解决方法:
- 组件组合 (Composition): 重新思考组件结构,看能不能把需要数据的组件作为
children传下去,而不是直接渲染。 - Context API: React 内置的解决方案,可以让你创建“全局”数据,在任何层级的子组件里都能直接访问,不用一层层传 props。适合中小型应用或传递主题、用户信息等。
- 状态管理库 (如 Redux, Zustand): 对于大型应用,或者有复杂共享状态的情况,可以使用专门的状态管理库,把状态集中管理。
- 组件组合 (Composition): 重新思考组件结构,看能不能把需要数据的组件作为
解决问题的通用方法:
- 仔细阅读错误信息! 浏览器控制台的报错通常会给出关键线索。
- 使用
console.log()或 Debugger: 在代码里打印变量,或者使用浏览器的开发者工具打断点,一步步看代码执行流程和变量值。 - React DevTools: 浏览器插件,可以查看组件树、props 和 state,非常有帮助。
- 缩小范围: 尝试注释掉一部分代码,或者创建一个最小的可复现问题的例子,定位问题源头。
- 搜索: 把错误信息或问题描述放到 Google 或 Stack Overflow 搜索,很可能别人也遇到过。
- 提问: 如果自己解决不了,向同事、导师或在线社区求助,记得说清楚你遇到的问题、你尝试过的方法和相关的代码。
新手建议: 遇到问题不要慌,这是学习过程的一部分。多用工具,多思考,多尝试。理解 React 的核心概念(如 State、Props、生命周期/Effect、不可变性)能帮你避免很多常见错误。
问:你对 React 的生态系统了解多少?
答:
React 本身只是一个用于构建用户界面的库(只负责视图 View 层)。但要开发一个完整的应用,我们还需要很多其他的工具和库,这些共同构成了 React 的“生态系统”。就像造汽车,光有引擎 (React) 不够,还需要轮子、方向盘、车身等等。
这个生态系统主要包括:
包管理器 (Package Managers):
- 干啥的? 用来安装和管理项目依赖的各种库(比如 React 本身、UI 库等)。
- 例子:
npm,yarn,pnpm - 好比: 汽车零件仓库的管理员。
构建工具 (Build Tools):
- 干啥的? 把你写的 React 代码 (JSX)、CSS、图片等转换、打包、优化成浏览器能直接运行的静态文件(HTML, CSS, JavaScript)。还能提供开发服务器,让你写代码时能实时看到效果。
- 例子:
Vite(现在非常流行,速度快),Create React App (CRA)(官方出品,曾经是标配,现在相对较少用于新项目),Next.js/Remix(这些是 React 框架,自带了构建能力)。 - 好比: 汽车的总装生产线。
路由 (Routing):
- 干啥的? 在单页面应用 (SPA) 中管理不同的“页面”或视图之间的跳转。虽然看起来像切换了页面,但实际上没有重新加载整个网页。
- 例子:
React Router(最常用),TanStack Router,Next.js Router(Next.js 内置)。 - 好比: 汽车的导航系统 (GPS)。
状态管理 (State Management):
- 干啥的? 当应用变得复杂,很多组件需要共享或修改同一份数据(状态)时,用来更方便、更可预测地管理这些状态。
- 例子:
React Context API(React 内置,适合简单场景),Redux(老牌、功能强大,适合大型复杂应用),Zustand(较新,更简洁易用),Jotai,Recoil。 - 好比: 汽车的中央控制系统,管理油量、速度等信息,仪表盘和引擎都能访问。
UI 库 / 组件库 (UI Libraries):
- 干啥的? (就是第一个问题提到的) 提供预先制作好的界面组件。
- 例子:
Material UI (MUI),Ant Design,Chakra UI,Tailwind CSS(这是一个 CSS 框架,常与 Headless UI 库如 Radix UI 结合使用)。 - 好比: 预制好的汽车座椅、仪表盘、按钮等零件。
测试库 (Testing Libraries):
- 干啥的? (就是第二个问题提到的) 用来写测试代码,保证应用质量。
- 例子:
Jest,React Testing Library (RTL),Cypress/Playwright(用于 E2E 测试)。 - 好比: 汽车出厂前的质量检测部门。
数据请求 (Data Fetching):
- 干啥的? 帮助你更方便地从服务器(API)获取数据,并处理加载状态、错误、缓存等。
- 例子:
fetch(浏览器内置),axios(流行的第三方库),TanStack Query (React Query)(非常强大,强烈推荐,能极大简化数据获取逻辑),SWR。 - 好比: 汽车加油或者从外部获取信息的系统。
新手建议: 生态系统很大,刚开始不需要全部掌握。通常,一个基础的 React 项目会用到:包管理器 (npm/yarn) + 构建工具 (Vite 是个好选择) + React 本身。如果需要多页面,就加上 路由 (React Router)。如果项目变大,状态共享困难了,再考虑引入 状态管理库。如果想省事,就用 UI 库。边学边用,按需引入就好。