React 项目场景题
场景 1:搜索输入触发频繁请求,页面闪动怎么办?
面试官可能这样问:
一个 React 搜索框,用户每输入一个字就请求接口,结果列表不断闪动,还可能出现旧结果覆盖新结果。你怎么处理?
回答思路:
- 输入值和请求值分离。
- 搜索请求加防抖。
- 每次请求记录 request id 或使用 AbortController 取消旧请求。
- loading、empty、error 状态要明确。
- 结果列表避免不必要重渲染。
项目化解释:
我会先用 useState 保存输入框实时值,再用防抖后的值触发请求。这样用户快速输入时不会每个字符都请求。
对于旧请求覆盖新请求的问题,我会使用 AbortController 或记录当前请求序号,只接受最后一次请求结果。否则网络慢时,用户输入 react,旧的 rea 结果可能后返回,把新结果覆盖掉。
追问点:
防抖 Hook 怎么写?
核心是延迟更新一个防抖后的值。输入值变化时设置定时器,下一次变化先清理旧定时器,只有用户停止输入一段时间后才触发请求。
useEffect 依赖怎么写?
依赖数组应该包含 effect 内部用到、并且来自组件作用域的响应式值。不要为了少执行而漏依赖,可以通过拆分 effect、稳定引用或移动逻辑来解决频繁执行问题。
AbortController 有什么作用?
它可以取消尚未完成的请求,避免旧请求继续占用资源,也避免旧响应覆盖新结果。搜索、筛选、切页场景都很适合使用。
React Query / SWR 能解决什么?
它们可以管理服务端状态,包括缓存、请求去重、重新验证、错误重试、分页和 loading 状态。适合减少手写请求状态管理。
场景 2:父组件更新导致很多子组件重复渲染怎么办?
面试官可能这样问:
一个 React 页面里父组件状态变化后,很多子组件都跟着渲染,页面变卡,你怎么优化?
回答思路:
- 先用 React DevTools Profiler 定位谁在频繁渲染。
- 把状态下沉到真正使用它的组件。
- 拆分大组件。
- 对渲染成本高且 props 稳定的组件使用
memo。 - 用
useMemo/useCallback保持对象和函数引用稳定。
项目化解释:
我不会一上来就到处加 memo。真实项目里我会先定位:是不是父组件放了太多状态,比如搜索框输入导致整个页面重渲染。如果是,就把搜索框状态下沉,或者拆出独立组件。
如果子组件确实很重,比如图表或大列表,再用 memo,并保证传给它的 props 不是每次都新建的对象。
追问点:
memo 为什么有时没效果?
memo 做的是 props 浅比较。如果父组件每次都传新对象、新数组、新函数,子组件仍然会重新渲染。
useCallback 是不是越多越好?
不是。useCallback 本身也有成本,只有当函数作为 props 传给 memo 组件,或作为 Hook 依赖导致明显问题时才更有价值。
Context 更新为什么会导致消费组件更新?
Context 的 value 变化时,所有消费该 Context 的组件都会重新渲染。可以拆分 Context、稳定 value 或使用更细粒度的状态管理减少影响。
如何判断优化是否有效?
用 React DevTools Profiler、性能指标和真实交互耗时判断。不要凭感觉优化,优化前后要能对比渲染次数和耗时。
场景 3:useEffect 写出死循环怎么办?
面试官可能这样问:
你在 React 项目里遇到过 useEffect 不断执行的问题吗?怎么排查?
回答思路:
- 检查依赖数组里是否有每次渲染都会变化的对象或函数。
- 检查 effect 中是否更新了依赖本身。
- 把派生数据改成
useMemo或直接在渲染中计算。 - 把事件逻辑从 effect 中移出去。
- 必要时拆分 effect。
项目化解释:
比如我见过这样的代码:组件里每次渲染都创建一个 params 对象,然后 useEffect 依赖它发请求。因为对象引用每次都变,所以 effect 一直执行。
解决方式是要么把 params 用 useMemo 包起来,要么让 effect 直接依赖原始字段,比如 page、keyword、status。
追问点:
为什么对象依赖会变化?
对象、数组、函数是引用类型,组件每次渲染时如果重新创建,引用就会变。即使内容一样,React 也会认为依赖变化。
useEffect 适合处理哪些副作用?
适合处理数据请求、订阅、定时器、手动 DOM 操作、浏览器 API 同步等会影响组件外部世界的逻辑。
哪些逻辑不应该放 useEffect?
纯计算、派生状态、事件处理、可以在渲染期间直接计算的内容不应该放 effect。否则容易增加状态同步复杂度。
StrictMode 为什么会让 effect 执行两次?
开发环境下 React 会故意重复执行部分生命周期和 effect,用来暴露副作用不安全的问题。生产环境不会这样重复执行。
场景 4:React 表单很多字段,如何设计?
面试官可能这样问:
一个 React 表单有几十个字段、动态校验、远程下拉选项,你会怎么设计?
回答思路:
- 简单表单可以受控组件。
- 复杂表单可以使用表单库,例如 React Hook Form。
- 校验规则集中管理。
- 远程选项要处理 loading、error 和缓存。
- 提交时做前端校验和后端错误回显。
项目化解释:
真实项目里,几十个字段都用 useState 会很难维护。我会把表单按模块拆成子组件,公共字段抽成配置,复杂校验放到 schema 或统一规则里。
后端返回字段错误时,也要能映射回具体输入框,而不是只弹一个“提交失败”。
追问点:
受控和非受控组件怎么选?
简单表单、需要实时联动和实时校验时受控更直观。字段很多、性能敏感时可以考虑非受控或表单库,减少每次输入导致的重渲染。
React Hook Form 为什么性能好?
它主要基于非受控组件和 ref 管理字段值,输入变化不一定触发整个表单重渲染,所以在大表单里性能更好。
如何处理动态表单?
用 schema 或配置描述字段、校验、显示条件和依赖关系。新增或删除字段时同步更新默认值、校验规则和提交转换逻辑。
如何防止重复提交?
提交中禁用按钮、展示 loading,并在请求层避免重复触发。关键接口仍要由后端做幂等,例如唯一 key 或状态机。