详尽的deps规则无法将自定义钩子的结果识别为React参考

时间:2019-10-23 12:59:27

标签: reactjs eslint typescript-eslint

想象一个钩子:

export function useMounted() {
    const mounted = React.useRef<boolean>(false);
    React.useEffect(() => {
        mounted.current = true;
        return () => {
            mounted.current = false;
        };
    }, []);
    return mounted;
}

我想使用该挂钩来确定是否仍在安装组件。它的一种用例是仅在浏览器获取并缓存了图像后才异步加载图像并显示图像。这种用例的简化版本可以是:

function useLazyImage(src: string, triggerCallback: any) {
    const mounted = useMounted();
    const image = useRef<HTMLImageElement>();

    useEffect(() => {
        if (!!src) {
            image.current = new Image();
            image.current.onload = () => {
                if (mounted.current)
                    triggerCallback();
            };
            image.current.src = src;
            return () => {
                image.current = undefined;
            };
        }
        return undefined;
    }, [src]);
}

它不包括错误处理,也不处理triggerCallback的更改,但这显示了我的问题。 react-hooks / exhaustive-deps警告我有关mounted依赖项的缺失,即使它不应该存在。由于mounted是Ref,因此通过使用它,我不会偶然关闭过时的作用域,而eslint实际上知道这一点。如果我将代码更改为

function useLazyImage(src: string, triggerCallback: any) {
    const mounted = React.useRef<boolean>(false);
    React.useEffect(() => {
        mounted.current = true;
        return () => {
            mounted.current = false;
        };
    }, []);
    const image = useRef<HTMLImageElement>();

eslint不再警告我。 ESLint的这种限制是它不知道我的自定义钩子是什么结果还是我做错了并且潜伏着一个错误?

1 个答案:

答案 0 :(得分:0)

在您的第一个示例中,您将从创建它的 useMounted 函数返回 ref。所以引用被泄露,因此可能会被更改。在您的底部示例中,引用是作为函数本地值创建的,因此不是组件状态的一部分。这就是为什么您没有看到底部示例中的警告。