React中如何实现移动端图片列表的按需加载?
在开发移动端图片列表时,我尝试用Intersection Observer实现按需加载,但发现滚动到可视区时图片没及时加载。我按教程写了代码,但控制台报”Uncaught TypeError: observer.observe is not a function”错误,这是为什么?
import { useRef, useEffect } from 'react';
function ImageList({ images }) {
const observer = useRef();
useEffect(() => {
observer.current = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 加载图片逻辑
}
});
});
const targets = document.querySelectorAll('.image-item');
targets.forEach(target => observer.current.observe(target));
}, []);
return (
);
}
export default ImageList;
我尝试过把observer.current改为直接创建实例,但滚动到页面底部时新加载的图片不会被观察。是不是需要在组件卸载时销毁观察器?或者Intersection Observer的使用时机哪里错了?
observer.current.observe这里,因为observer.current是一个对象而不是函数。我一般直接把观察器的创建和目标绑定逻辑分开写,这样更清晰。另外,确实需要在组件卸载时销毁观察器,不然会有内存泄漏的风险。直接用这个改好的代码:
这样写既解决了你的问题,也避免了内存泄漏。懒人开发就是追求简洁有效!
observer.observe报错是因为你在useEffect里重新赋值了observer.current,而useRef的初始值是undefined,导致第一次渲染时调用的是未定义的方法。其次,确实需要在组件卸载时销毁观察器,不然会造成内存泄漏。另外,你现在的写法会让所有图片都在一开始就被观察,这并不是按需加载的最佳实践。我们可以通过懒加载的方式,只对最后一个图片进行观察,当它进入视口时再加载下一批图片。
以下是改进后的代码:
);
}
export default ImageList;
这里的关键点:
1. 使用
lastImageRef来标记最后一个图片,只对它进行观察。2. 在
useEffect中清理之前的观察器实例,避免重复观察。3. 当最后一个图片进入视口时,断开当前观察并加载更多内容。
这样写更优雅,性能也更好,滚动体验会流畅很多。