如何在Flutter的initState中使用Provider实现条件性数据请求
问题解决方案:按需触发产品数据拉取逻辑
问题分析
当前代码的核心问题在于:仅在页面初始化时调用一次数据拉取,没有监听IsProductChangedProvider的状态变化,也未在拉取完成后更新状态值,导致无法实现"仅当isTheProductChanged为true时拉取数据,拉取后设为false"的逻辑。
修改步骤
1. 优化Provider状态管理
为IsProductChangedProvider新增明确的状态设置方法,避免使用toggle操作带来的歧义:
// is_products_changed_provider.dart import 'package:flutter/material.dart'; class IsProductChangedProvider extends ChangeNotifier { bool isTheProductChanged = true; // 保留原有状态切换功能(若需) void toggleChangedStatus() { isTheProductChanged = !isTheProductChanged; notifyListeners(); } // 明确设置状态为false,用于拉取完成后更新 void setChangedStatusFalse() { isTheProductChanged = false; notifyListeners(); } }
2. 调整Products页面逻辑
修改页面代码,实现状态监听、按需拉取及状态重置:
// products.dart import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:wineasy/components/error_card.dart'; import 'package:wineasy/components/side_nav_bar.dart'; import 'package:wineasy/components/single_product_card.dart'; import 'package:wineasy/models/product_model.dart'; import './is_products_changed_provider.dart'; // 确保路径正确 class Products extends StatefulWidget { const Products({Key? key}) : super(key: key); @override State<Products> createState() => _ProductsState(); } class _ProductsState extends State<Products> { Future<List<ProductModel>>? _futureProducts; @override Widget build(BuildContext context) { return Scaffold( drawer: const SideNavBar(), appBar: AppBar( backgroundColor: Colors.transparent, ), body: Consumer<IsProductChangedProvider>( builder: (context, provider, child) { // 当状态为true且无正在进行的请求时,触发数据拉取 if (provider.isTheProductChanged && _futureProducts == null) { _futureProducts = fetchProductData().whenComplete(() { // 拉取完成后重置状态 provider.setChangedStatusFalse(); // 清空请求实例,以便下次状态变化时重新触发 setState(() { _futureProducts = null; }); }); } // 初始化时无数据,主动触发一次拉取(可选,根据业务需求调整) if (!provider.isTheProductChanged && _futureProducts == null) { _futureProducts = fetchProductData(); } return FutureBuilder( future: _futureProducts, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 30.0), child: LinearProgressIndicator(), ), ); } else if (snapshot.hasError) { return const Center( child: ErrorCard(errorText: "Failed to load data"), ); } else if (snapshot.hasData) { List<ProductModel> productsList = snapshot.data as List<ProductModel>; return Padding( padding: const EdgeInsets.symmetric(horizontal: 15.0), child: GridView.builder( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 320, crossAxisSpacing: 15.0, mainAxisSpacing: 15.0, mainAxisExtent: 308 ), itemCount: productsList.length, itemBuilder: (context, index) { return SingleProductCard( productName: productsList[index].productName, productPrice: productsList[index].price, productType: productsList[index].typeOfProduct, productCategory: productsList[index].categoryOfProduct, productDescription: productsList[index].description, imageFile: productsList[index].imageFile, productId: productsList[index].productId, isAvailable: productsList[index].isAvailable, ); }, ), ); } else { return const Center(child: CircularProgressIndicator()); } }, ); }, ), ); } Future<List<ProductModel>> fetchProductData() async { const String getProductsUrl = "http://localhost:4848/api/product-list"; try { Response serverResponse = await Dio().get(getProductsUrl); List<ProductModel> productsList = (serverResponse.data as List<dynamic>) .map((productData) => ProductModel.fromJson(productData)) .toList(); return productsList; } catch (e) { print('Error fetching data: $e'); rethrow; } } }
核心修改说明
- 新增
setChangedStatusFalse方法:明确控制状态为false,避免toggle操作的不确定性 - 新增
_futureProducts变量:管理当前请求状态,防止重复触发接口调用 - 状态监听逻辑:在Consumer中实时监听
isTheProductChanged,满足条件时自动触发拉取 - 请求完成处理:拉取结束后立即重置状态,并清空请求实例,确保下次状态变化时能重新触发
内容的提问来源于stack exchange,提问作者Prasenjit Das
相关产品推荐
相关产品推荐

