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

React无限滚动重复加载前10条帖子问题排查求助

问题排查与修复

1. 后端Node.js代码问题

你的后端代码中,limitValue和skipValue直接从req.query获取,而req.query的参数类型是字符串,但Mongoose的limit()和skip()方法需要传入数字类型参数。如果不做类型转换,Mongoose会将字符串参数视为无效,默认使用0,导致无论传什么skip值,都只会返回前10条数据。

另外原代码中if (!posts)的判断逻辑不准确,Post.find()即使没有数据也会返回空数组而非null,应该用!posts.length判断是否无数据。

修复后的后端代码:

const getPosts = async (req, res) => {
  const { userId } = req.params;
  // 转换为数字,处理参数为非数字的情况
  const limitValue = parseInt(req.query.limit) || 10;
  const skipValue = parseInt(req.query.skip) || 0;
  const posts = await Post.find(userId ? { bookmarks: userId } : {})
    .sort({ createdAt: -1 })
    .populate("author")
    .populate("tags")
    .limit(limitValue)
    .skip(skipValue);

  if (!posts.length) res.status(204).json("No posts found");
  else {
    res.status(200).json(posts.map((post) => post.toObject({ getters: true })));
  }
};

2. React前端代码问题

你的前端fetchAgain函数中,skip参数被固定写为10,导致每次滚动都请求同一批次的数据,而不是根据当前已加载的帖子数量动态计算skip值。同时缺少加载状态控制,容易触发重复请求。

修复后的前端代码片段:

const PostsList = ({ filteredTag, toInvalidate, enableImages = true }) => {
  const advertise = async () => {
    window?.EventBus?.emit('reset-ads')
  }
  useEffect(() => {
    advertise()
  }, []);

  const [posts, setArticles] = useState(null);
  const [isLoading, setIsLoading] = useState(false); // 添加加载状态,防止重复请求

  useEffect(() => {
    const fetchAgain = async () => {
      if (posts == null || isLoading) return;
      setIsLoading(true);
      const skip = posts.length; // 动态计算skip值,等于当前已加载的帖子数
      try {
        const res = await fetch(`http://127.0.0.1:5000/posts?skip=${skip}`);
        const result = await res.json();
        if (result.length === 0) {
          console.log("没有更多帖子了");
          return;
        }
        // 使用函数式更新,避免依赖posts导致的状态更新问题
        setArticles(prevPosts => [...prevPosts, ...result]);
      } catch (err) {
        console.error("加载失败:", err);
      } finally {
        setIsLoading(false);
      }
    };

    const handleScroll = () => {
      const html = document.documentElement;
      const body = document.body;
      const windowheight = window.innerHeight || html.offsetHeight;
      const docHeight = Math.max(
        body.scrollHeight,
        body.offsetHeight,
        html.clientHeight,
        html.scrollHeight,
        html.offsetHeight
      );
      // 提前100px触发加载,提升用户体验
      const windowBottom = windowheight + window.pageYOffset;
      if (windowBottom >= docHeight - 100) {
        fetchAgain();
      }
    };

    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, [posts, isLoading]);

  useEffect(() => {
    setTimeout(async () => {
      const res = await fetch("http://127.0.0.1:5000/posts");
      const data = await res.json();
      setArticles(data);
      console.log(data);
    }, 2000);
  }, []);

  return (
    <Wrapper>
      {posts?.length > 0 ? (
        posts.map((post, i) => (
          <React.Fragment key={nanoid()}>
            <Post
              post={post}
              isFirstPost={enableImages && i === 0} {/* 修复索引判断逻辑,避免i++导致的混乱 */}
              filteredTag={filteredTag}
              toInvalidate={toInvalidate}
            />
            <Advertise />
          </React.Fragment>
        ))
      ) : <LoadingSpinner />}
      {isLoading && <LoadingSpinner />} {/* 显示加载状态 */}
    </Wrapper>
  );
};

总结

你的问题是前后端共同导致的:

  1. 后端未将query参数转换为数字,导致skip不生效,始终返回前10条数据
  2. 前端固定skip=10,即使后端修复后也会重复加载同一批数据

按照上述方案修复后,无限滚动应该能正常加载新数据。

内容的提问来源于stack exchange,提问作者samurai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 11:43:14