如何清理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>
);
};
我有这个组件,所以我想在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>
);
};