IntersectionObserver在React组件卸载后还会触发回调怎么办?

Zz炳钛 阅读 32

最近用IntersectionObserver做图片懒加载,发现组件被滚动出屏幕销毁后,observer居然还在触发回调!

代码是这样写的,useEffect里创建了observer,但组件卸载时没清理干净。试过在useEffect返回函数里调用disconnect,但好像没生效:


useEffect(() => {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        // 加载图片逻辑
        console.log('还在触发!')
      }
    });
  });
  observer.observe(targetRef.current);
  return () => observer.disconnect(); // 这样写对吗?
}, []);

控制台明明显示组件unmount了,但滚动页面时还是不断打印日志。是不是哪里没清理彻底?求大神指点!

我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
轩辕佼佼
你这个写法看着没问题,但 React 的 useEffect 返回函数执行时机是组件卸载时,如果你在组件卸载前没有手动 unobserve,那 targetRef 可能已经变成 null 或者被回收了,但 observer 本身没被正确移除目标,所以回调还会触发。

标准写法应该在组件卸载前不仅调用 disconnect(),还应该在返回函数中调用 observer.unobserve(targetRef.current),确保每个监听的目标都被正确移除。下面是修正后的代码:

useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 加载图片逻辑
console.log('图片加载中');
}
});
});

const target = targetRef.current;
if (target) {
observer.observe(target);
}

return () => {
if (target) {
observer.unobserve(target);
}
observer.disconnect();
};
}, []);


这样就能确保 observer 在组件卸载时不再触发回调。我之前也踩过这个坑,别以为 disconnect 就万事大吉了,目标元素得手动 unobserve 才算干净。
点赞 4
2026-02-04 23:36
W″雨橙
你这问题是因为observer还挂着呢,最简单的办法就是在unmount时先取消observe再disconnect。改下你的useEffect返回函数:

return () => {
if (targetRef.current) observer.unobserve(targetRef.current);
observer.disconnect();
};


这样就能确保彻底清理干净了,不会再触发回调。
点赞 14
2026-01-29 07:06