useEffect 在自定义钩子中使用 ref 缺少依赖项警告

Posted

技术标签:

【中文标题】useEffect 在自定义钩子中使用 ref 缺少依赖项警告【英文标题】:useEffect missing dependency warning with ref in custom hook 【发布时间】:2021-05-14 02:26:16 【问题描述】:

在启用了穷举规则的 React Typescript 中,当我定义一个 ref 并在效果内使用它时,linter 就可以了:

const stringRef: RefObject<string> = useRef("Hello World!");
  
useEffect(() => 
  console.log(stringRef.current);
, []) // no warning, the linter detects that I'm using a ref

但是,当我将效果放在自定义钩子中时,linter 抱怨我应该在依赖数组中包含 ref:

const stringRef: RefObject<string> = useRef("Hello World!");
  
useCustomHook(stringRef);

// in another-file.ts
const useCustomHook = (ref: RefObject<string>) => 
  useEffect(() => 
    console.log(ref.current);
  , []) // ESLint: React Hook useEffect has a missing dependency: 'ref'. Either include it or remove the dependency array.(react-hooks/exhaustive-deps)

从语义上讲,没有任何变化,但是,linter 无法识别 ref 是一个 RefObject(即使我是这样输入的)。

现在最大的问题是:我怎样才能让 linter 知道给定的依赖项不需要包含在依赖项数组中而不抑制警告?

对我来说,这是不可能的一个主要缺点,因为我无法在没有 linter 抱怨的情况下将我的效果转换为自定义钩子。

感谢您的帮助。

【问题讨论】:

我很好奇为什么会这样说。如果您的 ref.current 此处是非原始的而不是原始的字符串,您是否看到相同的行为? @LakshyaThakur 始终显示警告,当引用是对象或 dom 引用(htmlElement)时也是如此。但是 - 如前所述 - 仅适用于自定义效果(在额外文件中),当 ref 不在效果的周围范围内(但作为参数传递)时。如果 ref 在效果的周围范围内,则永远不会显示警告 useRef返回的ref对象不是稳定的吗?您可以安全地将其用作自定义效果中的依赖项 我同意@thedude,如果您确信 ref 是稳定的(它应该是稳定的,它是一个 ref),那么只需将其放入依赖数组中。除非重新声明 ref 本身,否则它不会触发 useEffect,这应该只在组件初始渲染时发生。如果您对它们的稳定性有信心,请不要害怕将东西放入依赖数组中。 感谢您的意见,我认为会有更聪明的方法来满足 linter。通过将 ref 添加为依赖项,即使它是一个 ref 我有点“污染”依赖项数组并分散对强制包含的依赖项的注意力。但是,嘿,我想我将不得不接受这个缺点! 【参考方案1】:

您不能开箱即用地对其进行配置。

linter (eslint) 是一个静态代码分析器。它只分析文本模式而不编译代码,即它不知道所写内容的“含义”。

例如,它看到“use***()”模式并认为它是一个自定义钩子,然后它使用“钩子规则”模式验证它,比如在if 语句中没有这样的文本。

自己看看:

提醒:自定义钩子是一个带有'use'前缀的函数一个使用钩子的函数。

// NOT A CUSTOM HOOK, just a function with 'use' prefix
const useConsole = () => console.log("hello");

// Normal function
const logHello = () => console.log("hello2");

const Component = () => 
  if (true) 
    // Warning - React hook is called conditionally
    useConsole();

    // OK
    logHello();
  
  return <>Example</>;
;

但是,您始终可以propose a custom rule 来识别同一范围内的RefObject&lt;string&gt;useEffect

在 Typescript 编译器方面,它没有违反任何内容,因为用例匹配 useEffect 类型。

【讨论】:

【参考方案2】:

useEffect1useEffect2 之间的区别在于 stringRef 是一个常量,因此根据定义 const 不会改变,但在示例中2 ref 是一个可以更改的变量,因此您必须将参数添加为依赖项。

【讨论】:

【参考方案3】:

您可以使用 // eslint-disable-next-line react-hooks/exhaustive-deps 禁用规则,否则您可以将 ref 移动到 useEffect 内

useEffect(() => 
   // other code
   ...

   // eslint-disable-next-line react-hooks/exhaustive-deps
, []) 

【讨论】:

如前所述,我不想抑制警告,因为那样我可能会错过未来需要添加的依赖项

以上是关于useEffect 在自定义钩子中使用 ref 缺少依赖项警告的主要内容,如果未能解决你的问题,请参考以下文章

在自定义反应钩子中使用 axios

状态变量钩子不适用于 useEffect 回调

React - nextjs 在 useEffect 中调用自定义钩子

使用 SetTimeout 测试自定义钩子,使用 Jest 测试 useEffect

使用自定义钩子封装 useEffect 和 AJAX 请求

在自定义钩子中访问 Redux 状态?