React分页加载时新数据追加失败怎么办?

诸葛静静 阅读 50

我在做一个商品列表分页,用useState存数据和页码,滚动到底部触发fetch请求。但第二次加载时新数据覆盖了旧数据而不是追加,控制台没报错,这是为什么呢?


const [items, setItems] = useState([]);
const [page, setPage] = useState(1);

useEffect(() => {
  const fetchMore = async () => {
    const res = await API.get(`/products?page=${page}`);
    setItems(res.data); // 这里是不是应该用函数式更新?
  };
  fetchMore();
}, [page]);

const handleScroll = () => {
  if (nearBottom) setPage(prev => prev + 1);
};

我试过把setItems写成setItems(prev => […prev, …res.data]),但这样每次刷新页面页码会重置,导致重复请求第一页的数据。有没有更好的状态管理方式?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
Des.晨羲
你的问题很常见。useState在处理异步更新时,如果直接依赖当前状态的值,容易出现状态不同步的问题,尤其是在分页加载这种场景。

你提到用setItems(prev => [...prev, ...res.data]),这其实是对的,但你说“每次刷新页面页码会重置,导致重复请求第一页的数据”,说明你可能在切换页面或组件卸载时没有重置状态。解决办法是在组件卸载时手动重置items和page。

另外,你在useEffect里面依赖page变化来触发fetchMore,这也没问题,但你得确保每次组件渲染时useEffect里面拿到的都是最新状态。

一个更清晰的做法是:

useEffect(() => {
let isMounted = true;

const fetchMore = async () => {
const res = await API.get(/products?page=${page});
if (isMounted) {
setItems(prev => [...prev, ...res.data]);
}
};

fetchMore();

return () => {
isMounted = false;
};
}, [page]);


然后在你监听滚动事件的地方:

useEffect(() => {
const handleScroll = () => {
if (nearBottom()) {
setPage(prev => prev + 1);
}
};

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


这样处理后,就能保证每次page变化都能拿到最新的items来追加数据。同时注意组件卸载时要清理事件监听器和中断异步请求。

至于你担心的“页码重置”问题,可以在组件卸载时手动setPage(1),或者在初始化useEffect的时候加个标志位判断page是否为1,避免重复请求。

分页加载就是得把状态管理清楚,不能全靠依赖自动触发。
点赞 4
2026-02-05 19:48
俊荣 Dev
你这个问题是典型的分页加载时状态管理没处理好。直接覆盖是因为每次调用setItems的时候没有保留旧数据,而使用函数式更新又会导致刷新页面时重复请求第一页。

解决办法是把页码和数据分开管理,并且在初始化时单独处理第一页的数据。代码放这了:

const [items, setItems] = useState([]);
const [page, setPage] = useState(1);

useEffect(() => {
const fetchMore = async () => {
const res = await API.get(/products?page=${page});
if (page === 1) {
setItems(res.data); // 第一页直接赋值
} else {
setItems(prev => [...prev, ...res.data]); // 后续页追加
}
};
fetchMore();
}, [page]);

const handleScroll = () => {
if (nearBottom) setPage(prev => prev + 1);
};


这样写能保证第一次加载时不会重复追加,后续分页正常追加数据。如果你还遇到问题,可能是API返回的数据格式不对,记得检查一下res.data是不是数组。
点赞 15
2026-01-31 02:55