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

Flutter:如何基于Provider构建可自动刷新的列表并解决现有问题?

正确实现方式

第一步:优化Provider,统一管理状态

将加载状态、错误信息与数据都交由Provider统一维护,避免页面自行维护状态导致的数据不同步问题:

class InventoryProvider extends ChangeNotifier {
  List<Item> _items = [];
  bool _isLoading = false;
  String _errorMessage = '';

  List<Item> get items => List.unmodifiable(_items);
  bool get isLoading => _isLoading;
  String get errorMessage => _errorMessage;

  Future<void> fetchAllItems() async {
    try {
      _isLoading = true;
      _errorMessage = '';
      notifyListeners(); // 通知UI进入加载状态

      _items = await ItemService().fetchAllItems();
    } catch (e) {
      _errorMessage = e.toString();
    } finally {
      _isLoading = false;
      notifyListeners(); // 通知UI加载完成/出现错误
    }
  }

  // 示例:详情页调用此方法删除条目
  Future<void> deleteItem(String itemId) async {
    try {
      await ItemService().deleteItem(itemId);
      _items.removeWhere((item) => item.id == itemId);
      notifyListeners(); // 删除后通知UI刷新列表
    } catch (e) {
      _errorMessage = e.toString();
      notifyListeners();
    }
  }
}

第二步:修改页面代码,监听Provider状态

页面不再自行维护数据与状态,直接从Provider获取并监听变化:

class InventoryScreen extends StatefulWidget {
  static const routeName = '/';

  const InventoryScreen({super.key});

  @override
  State<InventoryScreen> createState() => _InventoryScreenState();
}

class _InventoryScreenState extends State<InventoryScreen> {
  @override
  void initState() {
    super.initState();
    // 初始化仅调用数据获取方法,无需监听变化,故使用listen: false
    Provider.of<InventoryProvider>(context, listen: false).fetchAllItems();
  }

  @override
  Widget build(BuildContext context) {
    // 监听Provider变化,当notifyListeners调用时自动重建UI
    final inventoryProvider = Provider.of<InventoryProvider>(context);

    return Scaffold(
      appBar: AppBar(title: const Text('库存列表')),
      body: inventoryProvider.isLoading
          ? const Center(child: CircularProgressIndicator())
          : inventoryProvider.errorMessage.isNotEmpty
              ? Center(child: Text(inventoryProvider.errorMessage))
              : inventoryProvider.items.isEmpty
                  ? const Center(child: Text('暂无库存条目'))
                  : ListView.builder(
                      itemCount: inventoryProvider.items.length,
                      itemBuilder: (context, index) {
                        final item = inventoryProvider.items[index];
                        return ListTile(
                          title: Text(item.name),
                          // 示例:跳转到详情页
                          onTap: () {
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (context) => ItemDetailScreen(item: item),
                              ),
                            );
                          },
                        );
                      },
                    ),
    );
  }
}

关键说明

  • 状态统一管理:将加载、错误、数据状态全部放入Provider,确保所有依赖这些状态的UI能同步更新。
  • 正确使用listen参数:
    • initState中使用listen: false,仅用于初始化调用方法,无需监听后续变化;
    • build方法默认listen: true,Provider数据变化时会自动重建UI,实现列表刷新。
  • 避免无限循环:之前用didChangeDependencies出现循环,是因为每次依赖变化都会重新调用fetchAllItems,而方法内的notifyListeners又会触发依赖变化。现在将数据获取放在initState,仅执行一次。

内容的提问来源于stack exchange,提问作者nck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 02:12:11