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

Scroll Controller触发API重复调用,Loading判断失效如何解决?

解决滚动触发重复API请求的问题

问题根源分析

  1. Equatable状态字段未完全覆盖:你的PetsState继承了Equatable,但props数组中没有包含loading和fetched字段。这会导致Bloc在更新这两个字段时,Equatable认为状态没有变化,UI组件无法感知到loading状态的更新,滚动监听器里的!petsBloc.state.loading始终使用旧值,从而重复触发请求。
  2. 请求完成后未重置loading状态:Bloc处理请求时,仅在开始时将loading设为true,但请求结束后没有重置回false,不仅会导致后续无法触发新请求,也会让状态判断逻辑失效。
  3. 滚动监听器重复触发:滚动过程中scrollController的listener会被多次调用,若loading状态未及时同步到UI,每次滚动都会触发请求判断。

分步解决方案

1. 修复PetsState的Equatable匹配字段

修改pets_state.dart中的props,加入loading和fetched,确保状态变化能被正确检测:

@override
List<Object> get props => [lostPets, adoptionPets, foundPets, alertPets, userPosts, loading, fetched];

2. 完善Bloc的请求处理逻辑

在pets_bloc.dart中,给请求添加错误捕获,并在请求完成(无论成功失败)时重置loading状态;同时判断返回数据是否为空,标记是否已获取全部数据:

on<CollectionRequested>((event, emit) async {
  // 提前判断loading状态,直接拦截重复事件
  if (state.loading) return;

  emit(state.copyWith(loading: true));
  try {
    final List<PetModel> result =
        await petsRepository.getCollection(event.collection, event.page * 10);
    // 若返回空列表,标记为已获取全部数据
    final bool hasMore = result.isNotEmpty;

    switch (event.collection) {
      case 'lost':
        emit(state.copyWith(
          lostPets: [...state.lostPets, ...result],
          loading: false,
          fetched: !hasMore,
        ));
        break;
      case 'transit':
        emit(state.copyWith(
          foundPets: [...state.foundPets, ...result],
          loading: false,
          fetched: !hasMore,
        ));
        break;
      case 'adoption':
        emit(state.copyWith(
          adoptionPets: [...state.adoptionPets, ...result],
          loading: false,
          fetched: !hasMore,
        ));
        break;
    }
  } catch (e) {
    // 请求失败时重置loading状态,避免阻塞后续请求
    emit(state.copyWith(loading: false));
    // 可根据需求添加错误日志或状态提示
  }
});

3. 优化滚动监听器逻辑

在滚动监听器中增加fetched状态判断,避免无更多数据时继续触发请求;同时确保每次获取最新的Bloc状态:

@override
void initState() {
  super.initState();
  _scrollController.addListener(() {
    final ScrollPosition position = _scrollController.position;
    final petsBloc = BlocProvider.of<PetsBloc>(context);

    if (position.pixels >= position.maxScrollExtent - 500 &&
        selectedView.isNotEmpty &&
        !petsBloc.state.loading &&
        !petsBloc.state.fetched) {
      petsBloc.add(CollectionRequested(collection, page));
      setState(() {
        page++;
      });
    }
  });
}

内容的提问来源于stack exchange,提问作者Joaquín Varela

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:36:31