React 列表页一滚动,接口就一串串地发,是 useEffect 依赖里那个对象每次都换新吗?
接口在列表页反复请求,多数不是后端限流或请求库重试,而是 useEffect 的依赖数组里放了每次渲染都会新建的对象、数组或内联函数。React 比较依赖用的是引用相等,父组件或本组件每渲染一次就可能生成新引用,effect 便被判定为依赖变了;若 effect 内又 setState,还会形成「渲染—新引用—再执行—再渲染」的闭环。2026 年常见项目里,先分清是引用每轮变,还是 effect 读了过期值,再决定收窄依赖、固定引用或改结构,通常比直接清空依赖更稳。
React 比的是引用,不是内容
两个字段完全相同但分别新建的 {},在 React 眼里仍是两个不同对象。开发者说「值没变」,React 的结论是「引用变了」,这两句话不在同一层。常见触发源包括依赖里的对象字面量、数组字面量、内联箭头函数、父级整体下传的配置对象,以及 filter、map、sort 的返回值。它们不是写错,而是每次渲染都会产生新引用。
判断问题会不会升级成「停不下来」,看 effect 内有没有回写:有 setState、dispatch 或更新外部 store,才容易形成闭环;没有回写,通常表现为多跑几次。把这两类混在一起查,容易在错误方向上耗时间。
排查用「三看一验」,先找源头再改
重复请求有两个来源:引用每轮都变,或 effect 读到了过期值。先分清源头,能减少「请求次数对了、切换筛选后数据不更新」的返工。
- 一看依赖里有没有引用类型:对象、数组、内联函数、父级下传 props、filter/map 产物,命中先标记。
- 二看 effect 里有没有回写:有 setState、dispatch 或写外部 store,才可能闭环。
- 三看请求与渲染比例:在 Network 面板看请求条数是否随渲染次数增长,或在输入、滚动、切 tab 时成串出现。
- 一验:临时把依赖换成 id、status 这类原始值,或把常量提到组件外,看请求是否收敛到预期次数;验证因果后再定写法。
一验只用于确认因果。提到组件外的常量读不到 props 和 state;依赖检查规则的告警本身是线索,先想清楚补进去的是值还是引用,不必急着补。
四种写法与成本对比(经验区间)
同一个目标——让 effect 在预期时机执行——路径不止一条。差别在改动量、可读性和后续被改坏的风险。下面按项目出现频率排列,成本为常见区间,不是精确报价。
- 依赖收窄成原始值:把对象拆成 id、page、status 等字段。改动量通常较小,适合依赖只取少数字段;字段多时依赖数组会变长,建议加一句注释说明来源。
- useMemo / useCallback 固定引用:在产生方一侧缓存对象或函数。适合对象要整体传给子组件或被多个 effect 共用;坑在于 memo 自身依赖若还是新对象,缓存会失效,只是把问题往上挪一层。
- useRef 存最新值 + 空依赖:适合埋点、日志、只在挂载时读一次配置这类不需要因值变化而重跑的 effect;若业务要求筛选一变就重新请求,这条路会让数据不更新。
- 抽成自定义 hook 统一收口:把请求、依赖收敛、竞态处理封装一次,多处复用。适合同类请求出现 5 处以上的中后台项目,代价是额外维护一层抽象,新人要先读源码。
按一个中等复杂列表页(约 3~6 处相关 effect)估算:收敛依赖加回归的常见区间约 0.5~1.5 人日;顺带补竞态与卸载清理,再加约半天;自定义 hook 首建多花约半天到一天,但在 5 处以上复用时摊薄。排期时可按这个区间预留,而不是按「改一行依赖」估。
交付现场:联调窗口短时常见暴露点
在 2026 年常见交付节奏里,联调窗口只留 1~2 天、接口方按调用频率限流的情况并不少见。列表页挂上去后,切 tab、下拉都成串发请求,后端日志被打满,联调被迫停下来定位「谁在刷接口」。做法是上线前先跑一遍依赖自查,把依赖收敛为 id 加页码这类原始值,并在请求处加自增序号,回包时丢弃过期响应。结果通常是多花约半天做回归,换来上线首周少因限流被叫去救火;这类页面的定位常见区间约半小时到半天,整改常见区间约 0.5~1.5 人日。
另一个容易误判的现场是开发模式:开启 StrictMode 后 effect 会被有意执行两次,属预期行为,用来暴露缺少清理函数的问题。只在开发环境看到两次请求、生产只有一次,是正常的;若生产仍重复,再回到引用比较和闭环上排查。
适用与不适用边界
依赖收敛值得做,但不是每处 effect 都按同一标准处理。判断原则不是「依赖越全越好」,而是 effect 重跑一次的代价是否可接受:重跑只重建本地对象,和重跑会打接口、写日志、触发埋点,优先级不同。
- 适合较真:数据请求、订阅与解绑、埋点上报、三方 SDK 初始化,以及会写服务端状态的 effect。
- 不必较真:内联函数只在本地事件里用、没进依赖也没传给 memo 子组件;只在挂载时执行且不读 props 的初始化;纯展示组件里的一次性计算。
边界句:如果 effect 只有订阅和清理、且不读取会变化的外部变量,依赖留空是合理的;反过来,依赖里有引用类型又要求「只执行一次」,这两件事本身矛盾,应改结构,而不是继续加 memo。
常见问题
依赖里放了对象,用 useMemo 包一层是不是就不会重复请求了?
不一定。若 useMemo 的依赖里还有每轮新建的对象或函数,缓存会失效,请求照旧。先确认它的依赖是原始值,再看请求次数。
开发环境下同一接口请求两次,是 React 重复渲染导致的吗?
开启 StrictMode 时 effect 会被有意执行两次,属预期行为。若生产环境仍重复,再回到引用比较和 effect 内回写上排查。
把依赖数组清空能不能先减少请求?
能减少请求,但 effect 读到的是首次渲染的值,筛选或分页变化后数据可能不更新。适合临时定位,不宜当作长期写法。
输入框每敲一个字就发请求,也是依赖写错了吗?
多数不是引用问题,而是输入值进了依赖又没做防抖。引用问题改依赖结构,高频输入加防抖或改成提交时再请求。
如果手上有个请求次数异常的页面,先按「三看一验」确认因果,再决定收窄依赖、固定引用还是改结构;一次只动一处,改完看 Network 面板和切页告警。这套方法适用于以数据请求为主的 effect,纯展示或一次性初始化不必按同样标准返工。
-
2026年Uni-app跨端开发做到一半卡壳,该先查哪几项?
日期:2026年8月22日 阅读:209
-
2026年了,列表页用 keep-alive 保住筛选和滚动位置,从详情返回数据却还是旧的,返回时到底该不该每次重拉?
日期:2026年10月22日 阅读:91
-
2026年了,接口库存返回 0,页面却显示「--」,是前端把 0 当成没值了吗?
日期:2026年10月20日 阅读:38
-
2026年了,弹窗的灰色遮罩只盖住卡片那一块,周围页面还能点,是遮罩没铺满吗?
日期:2026年10月19日 阅读:96
-
AI 生成的弹窗和表单,键盘一按 Tab 就跑偏,2026 年上线前还值得花时间补焦点吗?
日期:2026年10月18日 阅读:98




