如何清理useEffect中的useRef?

How to cleanup useRef in useEffect?

我有这个组件,所以我想在useEffect中清理。我用谷歌搜索了这个问题,但没有有用的信息。

const LoadableImg = ({src, alt}) => {
const [isLoaded, setIsLoaded] = useState(false);

let imageRef = useRef(null);


useEffect(() => {
    if (isLoaded) return;
    if (imageRef.current) {
        imageRef.current.onload = () => setIsLoaded(true);
    }
    return () => {
        imageRef.current = null;
    };
}, [isLoaded]);

return (
    <div className={isLoaded ? 'l_container_loaded' : 'l_container'}>
        <img ref={imageRef} className={isLoaded ? "l_image_loaded" : 'l_image'}
             src={src}
             alt={alt}/>
    </div>
) };

我不知道如何在 useEffect 中清理。

更新 根据 Arcanus 的回答,添加了另一个 useEffect。

const LoadableImg = ({src, alt}) => {
const [isLoaded, setIsLoaded] = useState(false);

let imageRef = useRef(null);


useEffect(() => {
    if (isLoaded) return;
    if (imageRef.current) {
        imageRef.current.onload = () => setIsLoaded(true);
    }

}, [isLoaded]);

useEffect(() => {
    return () => {
        imageRef.current = null;
    };
},[])


return (
    <div className={isLoaded ? 'l_container_loaded' : 'l_container'}>
        <img ref={imageRef} className={isLoaded ? "l_image_loaded" : 'l_image'}
             src={src}
             alt={alt}/>
    </div>
)};

在您的实例中,您唯一想要使用 useEffect 的时间是 DOM 完全加载且您的引用已准备就绪时。因此你需要一个钩子

例如

function useHasMounted() {
  const [hasMounted, setHasMounted] = React.useState(false);
  React.useEffect(() => {
    setHasMounted(true);
  }, []);
  return hasMounted;
}

那么你的Component应该更正如下

const hasMounted = useHasMounted();

useEffect(() => {
        if (hasMounted) {
           imageRef.current.onload = () => setIsLoaded(true);
        }
}, [hasMounted]); //<-- call once when dom is loaded.

我知道您想在加载图像时调用 onload,但是,请注意这并不总是有效,因为从缓存加载的图像不会调用 onload

如果你想用 ref 做到这一点,那么你需要删除 onload 函数,但你不需要 null out imageRef.current:

useEffect(() => {
    if (isLoaded) return;
    const element = imageRef.current;
    if (element) {
        element.onload = () => setIsLoaded(true);
        return () => {
            element.onload = null;
        }
    }
}, [isLoaded]);

也就是说,我建议您不要为此使用参考。标准的 onLoad 道具也可以正常工作,不需要所有额外的逻辑来添加和删除事件侦听器:

const LoadableImg = ({ src, alt }) => {
  const [isLoaded, setIsLoaded] = useState(false);

  return (
    <div className={isLoaded ? "l_container_loaded" : "l_container"}>
      <img
        className={isLoaded ? "l_image_loaded" : "l_image"}
        src={src}
        alt={alt}
        onLoad={() => setIsLoaded(true)}
      />
    </div>
  );
};