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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:52:12