请求竞态处理:快速翻页与过期响应拦截
面试向讲清前端最真实的 bug 之一——请求竞态:为什么"后发"的请求可能"先至"、 旧响应如何覆盖新数据;三层解决方案(防抖减少 / AbortController 真取消 / 请求序号兜底); React useEffect cleanup + ignore flag 的官方写法与它为什么有效; 以及 loading 状态漏校验、ref 而非 state 存 requestId 等高频踩坑点。
面试向讲清前端最真实的 bug 之一——请求竞态:为什么"后发"的请求可能"先至"、 旧响应如何覆盖新数据;三层解决方案(防抖减少 / AbortController 真取消 / 请求序号兜底); React useEffect cleanup + ignore flag 的官方写法与它为什么有效; 以及 loading 状态漏校验、ref 而非 state 存 requestId 等高频踩坑点。
面试向讲透「setState 是同步还是异步」:更新同步入队、渲染异步批量; React 17 只在合成事件里批量,18 起 createRoot 全面自动批处理; 批处理窗口是一个同步执行块而非整个 async 函数;值形式与函数式更新的经典坑; flushSync 的语义与官方四条 caveat;以及类组件合并 vs hooks 替换。
面试向讲清 React 三代逻辑复用方案:HOC 高阶组件怎么才算写对(透传 props / displayName / 别在 render 里创建 / 转发 ref)、 Render Props 和 HOC 的本质区别是静态组合 vs 动态组合、自定义 Hook 共享的究竟是逻辑还是状态、 三者横向对比表,以及 Hooks 时代 HOC 和 Render Props 还有哪些场景不可替代。
面试向讲清 TanStack Query(React Query v5):服务端状态为什么不能塞进 Redux/Zustand、queryKey 为什么就是缓存地址、 staleTime 与 gcTime 到底差在哪、isPending / isFetching / isLoading 三个状态怎么区分、请求去重是怎么发生的、 invalidateQueries 默认只重拉 active 查询、以及乐观更新必须走的三步(cancel → 覆盖 → 回滚)。
面试向讲清 React 19 的 Actions 体系:useActionState 返回的三元组各自是什么、 dispatchAction 为什么必须包在 Transition 或 form action 里、useOptimistic 乐观值何时回滚、 useFormStatus 为什么必须写在 form 的子组件里、以及 Server Actions 的序列化边界与安全红线。
面试向讲清三件事:受控与非受控的本质是"谁持有状态"(React state 还是 DOM)、 只写 value 不写 onChange 为什么会变成只读输入框、受控/非受控这套思路同样适用于 Modal 等通用组件; 以及 createPortal 为什么能突破 overflow/z-index 却仍然按 React 树冒泡事件、共享 context。
面试向讲清 React 的渲染机制:re-render 到底做了什么(render ≠ 更新 DOM)、哪些操作会触发重渲染、 React 内置的两层 bailout(同值 setState 跳过、fiber 层跳过整棵子树)、 React.memo 的浅比较原理与它拦不住的三件事、以及比 memo 更根本的 state 下移与 children 提升。
面试向讲清 React 的 ref 三件套:useRef 到底是个什么盒子、改它为什么不触发渲染、它和 useState 怎么选; 为什么自定义组件默认拿不到 ref,React 18 的 forwardRef 和 React 19 的 ref as prop 有什么区别; useImperativeHandle 怎么只暴露必要方法,以及回调 ref 与 React 19 新增的 ref 清理函数。
面试向讲清 Context:它到底是"依赖注入"而不是状态管理、Provider 的值存在哪、useContext 是怎么向上查找并订阅的、 value 用 Object.is 比较带来的两大性能陷阱(新对象 / 全体消费者重渲染)、 四种优化手段(useMemo、拆 context、state 与 dispatch 分离、外部 store),以及 memo 为什么挡不住 context 更新。
面试向讲清 RSC:它和 SSR 到底有什么区别、'use client' 与 'use server' 两个指令各自标记什么、 RSC Payload 是怎么从服务端流到浏览器的、客户端组件为什么不能 import 服务端组件(children 组合模式怎么救)、 跨边界的值必须可序列化意味着什么,以及面试官最爱追问的"RSC 有什么代价"。