Heroku部署的React App在笔记本与台式机上表现不一致
MERN栈滚动加载图片重复问题的解决方法
我开发了一个基于MERN栈的图片展示应用,用来展示Cloudinary中带指定标签的图片(比如搜索"shoes"会返回对应标签的图片)。为实现滚动加载更多,我给窗口添加了滚动事件,当滚动条到底部时触发loadMore函数。这个功能在Mac台式机上正常,但在笔记本访问时会重复加载图片。已经确认滚动事件能正确检测到底部状态,nextCursor等变量也正常,但重复加载问题还是存在。
现有代码
滚动事件代码:
var totalPageHeight = document.body.scrollHeight; // @var int scrollPoint var scrollPoint = window.scrollY + window.innerHeight; // check if we hit the bottom of the page if(scrollPoint >= totalPageHeight) { if(nextCursor){ handleLoadMoreButtonClick() } }
加载更多图片代码:
console.log(`Prior to loading more images, next cursor is : ${nextCursor}`) if(nextCursor){ console.log("LOADING MORE IMAGES!!!!!!") const responseJson = await searchImages(query, nextCursor); setImageList((currentImageList) => [ ...currentImageList, ...responseJson.resources, ]); setNextCursor(responseJson.next_cursor); setNumImage(imageList.length+responseJson.resources.length) }
问题原因
笔记本屏幕高度较小,滚动到底部时,浏览器的滚动事件可能会连续触发多次。而React的setState是异步操作,第一次请求还没完成、nextCursor还没更新的时候,滚动事件又触发了handleLoadMoreButtonClick,导致用同一个旧的nextCursor重复请求,最终加载重复图片。
解决方案
1. 添加加载状态锁,防止重复触发请求
新增一个isLoading状态,在请求开始时锁定,请求完成后解锁,确保同一时间只有一个加载请求在进行:
// 新增加载状态 const [isLoading, setIsLoading] = useState(false); const handleLoadMoreButtonClick = async () => { console.log(`Prior to loading more images, next cursor is : ${nextCursor}`) // 只有当有nextCursor且未在加载时才执行 if(nextCursor && !isLoading){ console.log("LOADING MORE IMAGES!!!!!!") setIsLoading(true); // 加锁 try { const responseJson = await searchImages(query, nextCursor); setImageList((currentImageList) => [ ...currentImageList, ...responseJson.resources, ]); setNextCursor(responseJson.next_cursor); // 用函数式更新numImage,避免闭包拿到旧值 setNumImage(prevNum => prevNum + responseJson.resources.length); } catch (err) { console.error("加载更多图片失败:", err); } finally { setIsLoading(false); // 请求完成后解锁 } } };
2. 给滚动事件添加防抖处理
滚动事件触发频率很高,用防抖函数限制触发间隔,减少不必要的调用:
// 定义防抖函数 const debounce = (func, delay) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; }; // 用防抖包装滚动处理逻辑 const handleScroll = debounce(() => { const totalPageHeight = document.body.scrollHeight; const scrollPoint = window.scrollY + window.innerHeight; if(scrollPoint >= totalPageHeight) { // 加上isLoading判断,避免重复触发 if(nextCursor && !isLoading){ handleLoadMoreButtonClick(); } } }, 200); // 200ms延迟,可根据需求调整 // 组件挂载时添加监听,卸载时移除 useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [nextCursor, isLoading]); // 依赖项包含nextCursor和isLoading,确保状态变化时更新监听逻辑
总结
通过加载状态锁避免同一时间多次请求,加上防抖处理减少滚动事件的无效触发,再修正numImage的更新逻辑,就能解决笔记本上重复加载图片的问题。
内容的提问来源于stack exchange,提问作者jimmyshoo
相关产品推荐
相关产品推荐

