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> ); };
总结
你的问题是前后端共同导致的:
- 后端未将
query参数转换为数字,导致skip不生效,始终返回前10条数据 - 前端固定
skip=10,即使后端修复后也会重复加载同一批数据
按照上述方案修复后,无限滚动应该能正常加载新数据。
内容的提问来源于stack exchange,提问作者samurai
相关产品推荐
相关产品推荐

