Flutter中MultiProvider与Consumer导致页面频繁重建问题求助
Flutter Provider 导致Widget多次重建的解决办法
你的代码存在两个核心问题,直接导致了Widget重复重建:
问题分析
- 多余的Provider监听:在
ProductsScreen的build方法中,你调用了Provider.of<ProductsController>(context)(默认listen: true),但同时又用Consumer监听状态变化。这会让ProductsScreen在控制器状态更新时被触发两次重建,完全没必要。 - build方法中重复调用状态修改方法:
productsController.getProducts(ServerProducts())放在build里,每次Widget重建都会执行这个方法。而getProducts大概率会修改productsList并调用notifyListeners,这又会触发build,形成循环重建。
修改后的代码
方案1:改为StatefulWidget,将数据请求移到initState
class ProductsScreen extends StatefulWidget { const ProductsScreen({super.key}); @override State<ProductsScreen> createState() => _ProductsScreenState(); } class _ProductsScreenState extends State<ProductsScreen> { @override void initState() { super.initState(); // initState中获取控制器必须加listen: false,避免监听状态变化 final productsController = Provider.of<ProductsController>(context, listen: false); // 仅当列表为空时请求数据,避免重复请求 if (productsController.productsList.isEmpty) { productsController.getProducts(ServerProducts()); } } @override Widget build(BuildContext context) { return Consumer<ProductsController>(builder:(x, productsController, _){ return productsController.productsList.isEmpty ? const Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: productsController.productsList.length, itemBuilder: (ctx, index) => ProductCard( product: productsController.productsList[index], increaseByOne: () => productsController.increaseByOne(index), decreaseByOne: () => productsController.decreaseByOne(index), ), ); }); } }
方案2:保持StatelessWidget,用PostFrameCallback执行请求
如果你不想改成StatefulWidget,可以用WidgetsBinding的回调执行请求:
@override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { final productsController = Provider.of<ProductsController>(context, listen: false); if (productsController.productsList.isEmpty) { productsController.getProducts(ServerProducts()); } }); return Consumer<ProductsController>(builder:(x, productsController, _){ return productsController.productsList.isEmpty ? const Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: productsController.productsList.length, itemBuilder: (ctx, index) => ProductCard( product: productsController.productsList[index], increaseByOne: () => productsController.increaseByOne(index), decreaseByOne: () => productsController.decreaseByOne(index), ), ); }); }
额外优化建议
- 确保
ProductsController的getProducts方法中,只有当新数据与旧数据不一致时才调用notifyListeners,避免无意义的状态通知。 - 如果控制器是全局唯一的,可以在
main.dart中设置lazy: false,提前初始化控制器:
ChangeNotifierProvider(create: (ctx) => ProductsController(), lazy: false)
内容的提问来源于stack exchange,提问作者Mokhtar Ghaleb
相关产品推荐
相关产品推荐

