Skip to content

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 一直执行。

解决方式是要么把 paramsuseMemo 包起来,要么让 effect 直接依赖原始字段,比如 pagekeywordstatus

追问点:

为什么对象依赖会变化?

对象、数组、函数是引用类型,组件每次渲染时如果重新创建,引用就会变。即使内容一样,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 或状态机。

Built with VitePress and GitHub Pages.