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

ListView的onEndReached异常:重复加载数据且自动触发

解决ListView重复数据+onEndReached无需滚动触发的问题

兄弟,我之前踩过完全一样的坑!你遇到的重复数据问题,核心就是两个原因:

  • onEndReached无需滚动就触发:ListView初始渲染时,内容高度(contentSize)可能小于容器高度,组件直接判定已经到了底部,自动触发加载逻辑
  • API重复调用page=1:没有对请求做防抖锁,加上页码更新不及时,导致多次请求同一个页码的数据,最终重复拼接

具体修复方案

我给你整理了经过验证的代码和关键优化点:

1. 新增状态锁与分页控制

首先给组件添加isLoading(加载锁)和hasMore(是否还有更多数据)状态,彻底避免重复请求:

state = {
  categories: [],
  page: 1,
  isLoading: false, // 加载中锁,防止并发请求
  hasMore: true // 标记是否还有更多数据
};

2. 重构请求逻辑,用函数式setState避免闭包问题

因为setState是异步操作,直接用this.state可能拿到旧值,必须用函数式更新确保状态最新:

componentDidMount() {
  this.fetchCategories();
}

fetchCategories = async () => {
  // 加载中或无更多数据时直接返回,阻断重复请求
  if (this.state.isLoading || !this.state.hasMore) return;

  this.setState({ isLoading: true });
  try {
    const response = await categoryApi.getOne(this.state.page);
    if (response.data && response.data.data.length > 0) {
      // 函数式setState获取最新状态,避免闭包陷阱
      this.setState(prevState => ({
        categories: [...prevState.categories, ...response.data.data],
        page: prevState.page + 1, // 成功请求后才更新页码
        isLoading: false
      }));
    } else {
      // 没有更多数据了,关闭加载开关
      this.setState({
        isLoading: false,
        hasMore: false
      });
    }
  } catch (err) {
    console.error('分类数据请求失败:', err);
    this.setState({ isLoading: false });
  }
};

3. 配置ListView的关键属性

调整onEndReachedThreshold,避免初始误触:

render() {
  return (
    <ListView
      dataSource={new ListView.DataSource({ rowHasChanged: (r1, r2) => r1.id !== r2.id }).cloneWithRows(this.state.categories)}
      renderRow={(category) => <CategoryItem item={category} />}
      onEndReached={this.fetchCategories}
      onEndReachedThreshold={0.2} // 滚动到距离底部20%时触发,避免初始误触
      renderFooter={() => this.state.isLoading && <ActivityIndicator size="small" color="#000" />}
    />
  );
}

几个关键注意点

  • 加载锁必须生效:每次请求前先判断isLoading,防止用户快速滚动或者组件误触导致的重复请求
  • 页码更新时机:必须在请求成功后再更新页码,绝对不能提前加1(否则会出现请求page=2但还没拿到数据又触发page=3的情况)
  • rowHasChanged的正确实现:ListView的DataSource必须配置rowHasChanged,确保组件能正确识别数据变化,避免重复渲染

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:19:34