[英]Is it possible to avoid 'eslint(react-hooks/exhaustive-deps)' error on custom React Hook with useCallback?
Take the following custom React Hook to interact with IntersectionObserver
:使用以下自定义 React Hook 与
IntersectionObserver
交互:
import { useCallback, useRef, useState } from 'react';
type IntersectionObserverResult = [(node: Element | null) => void, IntersectionObserverEntry?];
function useIntersectionObserver(options: IntersectionObserverInit): IntersectionObserverResult {
const intersectionObserver = useRef<IntersectionObserver>();
const [entry, setEntry] = useState<IntersectionObserverEntry>();
const ref = useCallback(
(node) => {
if (intersectionObserver.current) {
console.log('[useInterSectionObserver] disconnect(🔴)');
intersectionObserver.current.disconnect();
}
if (node) {
intersectionObserver.current = new IntersectionObserver((entries) => {
console.log('[useInterSectionObserver] callback(🤙)');
console.log(entries[0]);
setEntry(entries[0]);
}, options);
console.log('[useInterSectionObserver] observe(🟢)');
intersectionObserver.current.observe(node);
}
},
[options.root, options.rootMargin, options.threshold]
);
return [ref, entry];
}
export { useIntersectionObserver };
ESLint is complaining about: ESLint 抱怨:
React Hook useCallback has a missing dependency: 'options'.
React Hook useCallback 缺少依赖项:'options'。 Either include it or remove the dependency array.
包括它或删除依赖数组。
If I replace the dependencies array with [options]
, ESLint no longer complains but there's now a much bigger problem, a rendering infinite loop .如果我用
[options]
替换依赖项数组,ESLint 不再抱怨,但现在有一个更大的问题,渲染无限循环。
What would be the right way to implement this custom React Hook without having the eslint(react-hooks/exhaustive-deps)
error showing up?在不出现
eslint(react-hooks/exhaustive-deps)
错误的情况下,实现这个自定义 React Hook 的正确方法是什么?
The fix to this is to destructure the properties you need from options
and set them in the dependancy array.对此的解决方法是从
options
中解构您需要的属性并将它们设置在依赖数组中。 That way you don't need options
and the hook only gets called when those three values change.这样你就不需要
options
,并且只有当这三个值发生变化时才会调用钩子。
import { useCallback, useRef, useState } from 'react';
type IntersectionObserverResult = [(node: Element | null) => void, IntersectionObserverEntry?];
function useIntersectionObserver(options: IntersectionObserverInit): IntersectionObserverResult {
const intersectionObserver = useRef<IntersectionObserver>();
const [entry, setEntry] = useState<IntersectionObserverEntry>();
const { root, rootMargin, threshold } = options;
const ref = useCallback(
(node) => {
if (intersectionObserver.current) {
console.log('[useInterSectionObserver] disconnect(🔴)');
intersectionObserver.current.disconnect();
}
if (node) {
intersectionObserver.current = new IntersectionObserver((entries) => {
console.log('[useInterSectionObserver] callback(🤙)');
console.log(entries[0]);
setEntry(entries[0]);
}, options);
console.log('[useInterSectionObserver] observe(🟢)');
intersectionObserver.current.observe(node);
}
},
[root, rootMargin, threshold]
);
return [ref, entry];
}
export { useIntersectionObserver };
You should always provide all the necessary values in the dep array to prevent it from using the previous cached function with stale values.您应该始终在 dep 数组中提供所有必要的值,以防止它使用以前缓存的 function 和陈旧的值。 One option to fix your situation is to memo the
options
object so only a new one is being passed when it's values change instead of on every re-render:解决您的情况的一种选择是记下
options
object 以便在其值更改而不是每次重新渲染时仅传递一个新选项:
// in parent
// this passes a new obj on every re-render
const [ref, entry] = useIntersectionObserver({ root, rootMargin, threshold });
// this will only pass a new obj if the deps change
const options = useMemo(() => ({ root, rootMargin, threshold }), [root, rootMargin, threshold]);
const [ref, entry] = useIntersectionObserver(options);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.