是否可以使用 useCallback 避免自定义 React Hook 上的'eslint(react-hooks/exhaustive-deps)'错误?



使用以下自定义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正在抱怨:

React Hook useCallback缺少依赖项:"options"。请将其包括在内或删除依赖项数组。

如果我用[options]替换依赖项数组,ESLint不再抱怨,但现在有一个更大的问题,渲染无限循环

在不出现eslint(react-hooks/exhaustive-deps)错误的情况下,实现这个自定义React Hook的正确方法是什么?

解决方法是从options中销毁所需的属性,并将其设置在dependency数组中。这样就不需要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 };

您应该始终在dep数组中提供所有必要的值,以防止它使用带有过时值的前一个缓存函数。解决这种情况的一个选项是记下options对象,这样当它的值发生变化时,而不是每次重新渲染时,只传递一个新对象:

// 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); 

最新更新