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<string>
和useEffect
。
在 Typescript 编译器方面,它没有违反任何内容,因为用例匹配 useEffect
类型。
【讨论】:
【参考方案2】:useEffect1 和 useEffect2 之间的区别在于 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 缺少依赖项警告的主要内容,如果未能解决你的问题,请参考以下文章
React - nextjs 在 useEffect 中调用自定义钩子