Flutter Provider:数据更新时notifyListener()多次调用问题求修复
解决Provider中notifyListener()多次调用的问题
问题根源
你当前的核心问题是在Consumer的builder方法里直接调用了product.getAllProduct()。而builder会在以下场景反复执行:
- Widget首次构建
- Provider调用
notifyListeners()时 - 父Widget触发重建时
这就形成了无限循环:调用getAllProduct() → 数据更新调用notifyListeners() → 触发builder重建 → 再次调用getAllProduct() → 再次触发notifyListeners()...
修复方案
方案1:将数据初始化移到生命周期方法(推荐)
把数据获取逻辑从builder移到initState(仅适用于StatefulWidget),这样只会执行一次:
class YourProductWidget extends StatefulWidget { @override State<YourProductWidget> createState() => _YourProductWidgetState(); } class _YourProductWidgetState extends State<YourProductWidget> { @override void initState() { super.initState(); // 在这里调用数据获取,仅执行一次 Provider.of<ProductData>(context, listen: false).getAllProduct(); } @override Widget build(BuildContext context) { return Consumer<ProductData>(builder: (context, product, child) { final productList = product.list; return Container( height: 250, padding: EdgeInsets.only(top: 20), child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: productList.length, itemBuilder: (context, index) { return ItemsProduct( img: productList[index].img, price: productList[index].price, name: productList[index].name); }, ), ); }); } }
注意:使用Provider.of时要加listen: false,因为这里只需要调用方法,不需要监听状态变化(监听逻辑交给Consumer即可)。
方案2:给Provider添加加载状态,避免重复请求
如果需要支持下拉刷新、重新加载等场景,可以给ProductData添加加载状态标记,防止重复调用API:
class ProductData with ChangeNotifier{ List<Product> _list =[]; List<Product> get list => _list; bool _isLoading = false; // 新增加载状态标记 bool get isLoading => _isLoading; getAllProduct() async{ if(_isLoading) return; // 正在加载时直接返回,避免重复请求 _isLoading = true; try{ _list = await fetchProduct(); notifyListeners(); }finally{ _isLoading = false; // 无论请求成功失败,都重置加载状态 } } }
之后在Widget里还可以根据isLoading显示加载动画,提升用户体验。
额外优化:修复API请求的空值风险
你的fetchProduct方法在请求失败/异常时返回productList!,存在空指针崩溃风险,建议优化:
Future<List<Product>> fetchProduct() async{ final url = "http://192.168.55.102:3000/product/getAllProducts"; try{ final response = await http.get(Uri.parse(url)); if(response.statusCode == 200){ final product = jsonDecode(response.body) as List; return product.map<Product>((e) => Product.formJson(e)).toList(); }else{ print('请求失败,状态码:${response.statusCode}'); return []; // 返回空列表而非null } }catch(err){ print('请求异常:$err'); return []; // 返回空列表而非null } }
内容的提问来源于stack exchange,提问作者Quang Nguyễn
相关产品推荐
相关产品推荐

