Flutter基于Future<void>实现分页时无限加载问题求助
问题排查与修复方案
核心问题分析
你的代码出现无限加载的原因主要有三点:
- FutureBuilder滥用导致重复请求:直接将
fetchItems()传入FutureBuilder的future参数,每次组件build(比如setState后)都会重新执行fetchItems(),触发不必要的API请求,形成循环。 - 滚动监听缺少加载状态判断:滚动到底部的判断逻辑仅检查了
hasMore,未排除isLoading状态,导致加载过程中只要滚动位置满足条件就会重复调用请求。 shrinkWrap属性干扰滚动计算:GridView设置shrinkWrap: true会让列表高度自适应内容,可能导致maxScrollExtent计算不准确,频繁触发底部判断。
修复后的代码
构建方法修改
Widget build(BuildContext context) { return Center( child: NotificationListener<ScrollNotification>( onNotification: (ScrollNotification scrollInfo) { // 提前10%触发加载,同时排除加载中状态 if (scrollInfo.metrics.pixels >= scrollInfo.metrics.maxScrollExtent * 0.9 && hasMore && !isLoading) { fetchItems(); } return true; }, child: _buildContent(), ), ); } // 拆分UI构建逻辑,提升可读性 Widget _buildContent() { if (categoyItems == null || categoyItems!.isEmpty) { return isLoading ? const Center(child: CircularProgressIndicator()) : const Center(child: Text('No states available')); } return GridView.custom( padding: const EdgeInsets.symmetric(vertical: 10), gridDelegate: const SliverStairedGridDelegate( mainAxisSpacing: 6, crossAxisSpacing: 8, pattern: [ StairedGridTile(0.53, 0.8), StairedGridTile(0.470, 0.8), StairedGridTile(0.470, 0.8), StairedGridTile(0.53, 0.8), ], ), childrenDelegate: SliverChildBuilderDelegate( childCount: categoyItems!.length + (hasMore ? 1 : 0), (context, index) { if (index == categoyItems?.length) { return const Center(child: CircularProgressIndicator()); } final item = categoyItems![index]; return Container(....); // 保留你的原有组件逻辑 }, ), ); }
API请求方法无需修改(已具备加载状态控制)
你的fetchItems()方法已经通过isLoading做了防重复请求处理,无需改动。
关键修改点说明
- 移除FutureBuilder:直接通过组件状态(
isLoading、categoyItems)构建UI,避免每次build触发重复请求。 - 优化滚动监听逻辑:添加
!isLoading判断防止加载中重复请求;将触发时机改为滚动到90%位置,提升用户体验同时避免边界条件误触发。 - 移除
shrinkWrap: true:让GridView使用默认的滚动布局逻辑,保证滚动参数计算准确。
内容的提问来源于stack exchange,提问作者Emad Younan
相关产品推荐
相关产品推荐

