首页 > 解决方案 > 是否可以通过 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 的正确方法是什么?

标签: reactjsreact-hookseslint

解决方案


解决此问题的方法是解构您需要的属性options并将它们设置在依赖数组中。这样你就不需要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 };

推荐阅读