4

想象一个钩子:

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依赖项,即使它不应该 afaik。因为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 的这种限制是它无法知道我的自定义钩子的结果是什么,还是我做错了,并且潜伏着一个错误?

4

1 回答 1

0

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

于 2021-07-12T15:36:32.487 回答