You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 14:57:22