Flutter中Provider无限执行导致列表数据无限追加问题如何解决?
问题根本原因
build方法会在组件状态变化时反复执行,你直接在build中调用fetchCartByUser,同时Provider.of<CartProvider>(context)默认会监听Provider的状态变化,只要Provider调用notifyListeners就会触发当前组件重绘,重绘又会再次调用fetchCartByUser,请求完成后又触发notifyListeners,最终形成死循环。fetchCartByUser拉取新数据时,直接用insert往_cartItems列表中追加数据,没有先清空旧数据,所以每次调用接口都会重复插入相同的购物车数据,导致列表内容重复累加。
解决步骤
1. 调整数据请求的调用时机,不要在build方法中发请求
将请求逻辑放到initState中,确保页面初始化时仅执行一次,同时获取Provider时设置listen: false,避免监听状态变化触发不必要的重绘。
修改后的页面代码示例:
// 页面需要改为StatefulWidget class CartPage extends StatefulWidget { const CartPage({super.key}); @override State<CartPage> createState() => _CartPageState(); } class _CartPageState extends State<CartPage> { String? phoneNumber; late String testString; bool isEmpty = false; @override void initState() { super.initState(); // 初始化阶段仅执行一次请求 final FirebaseAuth _auth = FirebaseAuth.instance; User? user = _auth.currentUser; phoneNumber = user?.phoneNumber; // listen设为false,不会因为Provider状态变化触发当前组件重绘 final cartProvider = Provider.of<CartProvider>(context, listen: false); if(phoneNumber != null) { cartProvider.fetchCartByUser(phoneNumber!); } } @override void didChangeDependencies() { super.didChangeDependencies(); // ModalRoute需要等组件依赖初始化完成后获取,不能放在initState中 testString = ModalRoute.of(context)!.settings.arguments as String; } @override Widget build(BuildContext context) { // build中仅获取数据,不要执行请求方法 final cartProvider = Provider.of<CartProvider>(context); isEmpty = cartProvider.cartItems.isEmpty; return isEmpty ? Scaffold(body: CartEmpty()) : Scaffold( // 你的购物车页面布局逻辑 ); } }
2. 修改fetchCartByUser方法,拉取新数据前清空旧列表
避免重复插入数据,修改后的Provider代码:
Future<void> fetchCartByUser(String phoneNumber) async { // 先清空旧的购物车数据,防止重复累加 _cartItems.clear(); await Server.getCartData().then((value) { for(var item in value) { _cartItems.insert( 0, CartModel( cartId: item['cartId'], clientAddress: item['clientAddress'], clientFullname: item['clientFullname'], clientPhoneNumber: item['clientPhoneNumber'], createdAt: item['createdAt'], merchant: item['merchant'], merchantCode: item['merchantCode'], price: item['price'], productCode: item['productCode'], productImage: item['productImage'], productName: item['productName'], productQty: item['productQty'], productSKU: item['productSKU'], ), ); } }); notifyListeners(); }
可选优化:增加请求状态锁,防止重复触发请求
如果存在多个场景可能触发购物车刷新,可以加请求状态标记,避免短时间重复调用接口:
class CartProvider with ChangeNotifier { List<CartModel> _cartItems = []; bool _isLoading = false; // 对外暴露加载状态,可用于页面展示加载动画 bool get isLoading => _isLoading; List<CartModel> get cartItems { return [..._cartItems]; } CollectionReference cart = FirebaseFirestore.instance.collection('cart'); Future<void> fetchCartByUser(String phoneNumber) async { // 正在请求中直接返回,避免重复调用 if(_isLoading) return; _isLoading = true; notifyListeners(); _cartItems.clear(); try { final value = await Server.getCartData(); for(var item in value) { _cartItems.insert(0, CartModel(/* 和之前的参数一致 */)); } } catch(e) { // 自行处理请求异常逻辑 } finally { _isLoading = false; notifyListeners(); } } // 剩余的deleteSingleCart、updateProductQty、totalAmount逻辑保持不变 }
内容的提问来源于stack exchange,提问作者Amitha Mohanan
相关产品推荐
相关产品推荐

