使用 ref 的自定义 hook 中出现了 useEffect 缺少依赖项警告

7
在启用exhaustive-deps规则的React Typescript中,当我定义一个ref并在effect内部使用它时,语法检查器会认为这是正确的:
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知道给定的依赖项不需要包含在依赖项数组中,而不会抑制警告?

对我来说,这是一个主要的缺点,因为我无法将我的effects转换为自定义hooks,而不被linter抱怨。

感谢您的帮助。


我很好奇为什么它会这样说。如果你的 ref.current 是一个非原始类型而不是像字符串一样的原始类型,你是否看到相同的行为? - Lakshya Thakur
@LakshyaThakur 警告始终显示,无论引用是对象还是 DOM 引用(HTMLElement)。但是 - 如已经说明的那样 - 仅在自定义效果(在额外文件中)中,当引用不在效果的周围作用域中(而是作为参数传递)时才会出现警告。如果引用在效果的周围作用域中,则永远不会显示警告。 - Boris Pöhland
3
useRef 返回的 ref 对象不稳定吗?你可以将其安全地用作自定义 effect 中的依赖项。 - thedude
1
我同意@thedude的观点,如果你有信心ref是稳定的(它应该是稳定的,因为它是一个ref),那么就把它放在依赖数组中。它不会触发useEffect,除非ref本身被重新声明,这只会发生在组件的初始渲染时。如果你对它们的稳定性有信心,就不要害怕把东西放在依赖数组中。 - Cal Irvine
感谢您的输入,我认为有更聪明的方法来满足代码检查器。即使它是一个 ref,通过将其添加为依赖项,我也会在某种程度上“污染”依赖项数组,并分散对必须包含的依赖项的注意力。但是,嘿,我想我必须接受这个缺点! - Boris Pöhland
3个回答

2

你不能直接配置它。

代码检查工具(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</>;
};

Edit Eslint Example

但是,你总是可以提出自定义规则来识别在同一范围内的RefObject<string>useEffect
从TypeScript编译器的角度来看,这并不违反任何规定,因为使用情况符合useEffect类型。

0

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


-4

你可以使用 // eslint-disable-next-line react-hooks/exhaustive-deps 禁用该规则,或者将 ref 放在 useEffect 内部

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

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

正如已经提到的,我不想压制警告,因为这样可能会错过未来需要添加的依赖关系。 - Boris Pöhland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接