You need to enable JavaScript to run this app. 如何使用useState实现无限滚动分页时向现有对象列表追加新数据
优惠活动
大模型
产品
解决方案
定价
更多

如何使用useState实现无限滚动分页时向现有对象列表追加新数据

无限滚动分页状态追加的实现修正

问题本质

执行setItems(resources)的写法,本质是用新拉取的数组整体替换了原有的items状态,这是React useState更新的默认逻辑——只要给状态更新函数传入一个确定的值,它就会直接替换掉之前存储的状态,不会自动执行数组合并。
滚动后触发页面刷新的异常,通常来自两个常见问题:

  • 没有通过isFetching做请求节流拦截,短时间内多次触发状态更新导致渲染异常
  • 滚动加载的触发源如果是锚点、提交按钮类标签,没有阻止默认行为时会触发页面跳转/提交,表现和页面刷新一致

修正实现

要实现新旧数据的追加合并,需要使用useState的 函数式更新 能力:给setItems传入一个回调函数,回调的入参是当前内存中最新的旧状态值,把旧数组和新拉取的数组合并后返回,作为新的状态值。
同时需要补齐几个关键的逻辑修正:

  • 在函数入口处加isFetching判断,上一批数据还在加载时直接中断执行,避免重复发请求
  • 把isFetching的重置逻辑放到请求的最终回调里,不要和定时器逻辑硬绑定,避免请求还没完成就提前重置状态触发重复请求
  • 对初始值为undefined的items状态做空值兜底,避免出现读取未定义属性的报错

修正后的代码参考:

function fetchMoreListItems() {
  // 加载中直接拦截,杜绝重复请求
  if (isFetching) return;
  setIsFetching(true);

  setTimeout(() => {
    if (!props.resource) {
      setIsFetching(false);
      return;
    }
    props.resource
      .follow('activities-collection').follow('next').followAll('item')
      .then(resources => {
        // 函数式更新:获取最新旧状态后做数组拼接
        setItems(prevItems => {
          // 兜底初始空状态,直接返回首批拉取结果
          return prevItems ? [...prevItems, ...resources] : resources;
        });
      })
      .catch(err => console.error('Error fetching resources: ' + err))
      // 请求不管成功失败,最终都重置加载状态
      .finally(() => setIsFetching(false));
  }, 1000);
}

常见避坑点

  • 不要直接引用外部作用域的items变量做拼接操作,受闭包特性影响,很可能拿到陈旧的状态值,导致新数据被意外覆盖;使用函数式更新可以保证拿到的永远是最新的状态值
  • 检查滚动触发源的DOM属性,如果是带href的锚点元素或者type="submit"的按钮,绑定事件时需要加preventDefault()阻止默认跳转行为,这是很多场景下出现“自动页面刷新”表现的核心原因
  • 当拉取到最后一页、不存在next关联关系时,记得主动移除滚动监听,避免发起无意义的空请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 19:54:04