You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义useChanges钩子补全useEffect依赖无限循环,如何符合ESLint规范?

问题根因

你遇到的无限循环是因为getChangedItemAndOriginalItem和applyChanges两个函数每次组件渲染时都会生成新的引用,加入useEffect依赖数组后,每次函数引用变化就会触发useEffect执行,执行逻辑又导致组件重渲染生成新的函数,陷入死循环。

方案1:补全自定义hook内部的useCallback依赖

首先在useChanges自定义hook内部,将两个返回的函数用useCallback包裹,同时把函数内部用到的所有外部变量都补全到useCallback的依赖数组中,确保依赖无变化时函数引用不会更新:

// useChanges 内部实现示例
import { useCallback } from 'react'

function useChanges(initialChanges, originalItems, selector) {
  // 其他内部逻辑...

  const getChangedItemAndOriginalItem = useCallback(() => {
    // 原有函数逻辑
  }, [originalItems, selector]) // 补全所有内部用到的外部变量

  const applyChanges = useCallback((newValues) => {
    // 原有函数逻辑
  }, [getChangedItemAndOriginalItem]) // 依赖的内部函数也要加入

  return { getChangedItemAndOriginalItem, applyChanges }
}

如果作为参数传入的selector函数是在父组件内定义的,也需要用useCallback包裹,避免每次渲染生成新引用导致hook内部的useCallback重新生成函数。

方案2:用useRef存储函数引用规避依赖校验

如果不想改动自定义hook的内部逻辑,可以在组件内用useRef保存函数的最新引用,业务useEffect只需要依赖debouncedValues即可:

// 组件内使用示例
const { applyChanges } = useChanges(/* 你的入参 */)
const applyChangesRef = useRef(applyChanges)

// 同步最新的函数引用
useEffect(() => {
  applyChangesRef.current = applyChanges
}, [applyChanges])

// 业务逻辑useEffect
useEffect(() => {
  applyChangesRef.current(debouncedValues)
}, [debouncedValues])

该写法逻辑正确,且完全符合ESLint的依赖校验规则。

方案3:使用useEvent(React 18+ 官方解决方案)

如果使用React 18及以上版本,可以直接用useEvent(目前为实验性API,后续会正式纳入稳定版)包裹不需要响应式更新的函数,它会始终返回同一个引用,不需要加入useEffect依赖数组:

// useChanges 内部实现示例
import { useEvent } from 'react'

function useChanges(initialChanges, originalItems, selector) {
  // 其他内部逻辑...

  const applyChanges = useEvent((newValues) => {
    // 原有函数逻辑
  })
}

这个API就是为了解决「事件类函数不需要加入useEffect依赖」的场景设计的,完全符合官方规范和ESLint校验规则。

内容的提问来源于stack exchange,提问作者Martin Hofhanzl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 16:15:02