Scroll Controller触发API重复调用,Loading判断失效如何解决?
解决滚动触发重复API请求的问题
问题根源分析
- Equatable状态字段未完全覆盖:你的
PetsState继承了Equatable,但props数组中没有包含loading和fetched字段。这会导致Bloc在更新这两个字段时,Equatable认为状态没有变化,UI组件无法感知到loading状态的更新,滚动监听器里的!petsBloc.state.loading始终使用旧值,从而重复触发请求。 - 请求完成后未重置loading状态:Bloc处理请求时,仅在开始时将
loading设为true,但请求结束后没有重置回false,不仅会导致后续无法触发新请求,也会让状态判断逻辑失效。 - 滚动监听器重复触发:滚动过程中
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
相关产品推荐
相关产品推荐

