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

Flutter:使用Riverpod StateProvider删除列表项后UI无法实时更新

Flutter Riverpod 删除列表项后 UI 无法实时更新的解决方案

问题核心原因

  1. FutureBuilder 仅单次执行:原代码中FutureBuilder仅在页面首次构建时调用productRepository.getAll(),删除操作不会触发其重新执行,导致UI无法获取最新数据。
  2. 状态更新未触发监听:直接修改StateProvider持有的列表实例(productList.remove(product)),即使调用update,由于列表是同一个引用,Riverpod无法检测到状态变化,不会通知UI刷新。
  3. UI未绑定状态监听:productListTile使用的是FutureBuilder返回的本地列表,而非监听StateProvider的状态,状态更新无法同步到UI。

修正后的代码实现

1. 定义StateNotifier管理状态

import 'package:flutter_riverpod/flutter_riverpod.dart';

class ProductListNotifier extends StateNotifier<List<Product>> {
  ProductListNotifier() : super([]) {
    // 初始化时加载数据
    _loadProducts();
  }

  final ProductRepository productRepository = ProductRepository();

  // 从数据库加载产品列表
  Future<void> _loadProducts() async {
    final products = await productRepository.getAll();
    // 赋值新列表实例,触发状态更新
    state = products;
  }

  // 删除产品并更新状态
  Future<void> deleteProduct(int productId) async {
    // 先删除数据库数据
    await productRepository.delete(productId);
    // 创建新列表移除目标产品,触发UI刷新
    state = state.where((product) => product.id != productId).toList();
  }
}

// 提供状态给UI使用
final productListProvider = StateNotifierProvider<ProductListNotifier, List<Product>>((ref) {
  return ProductListNotifier();
});

2. 修改ProductScreen组件

class ProductScreen extends ConsumerWidget with FilteredList {
  ProductScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final searchText = ref.watch(searchTextProvider);
    return Scaffold(
      floatingActionButton: createProductButton(context),
      appBar: AppBar(
        title: const Text("Tela de Produtos"),
      ),
      body: Column(
        children: [
          searchProductField(ref),
          const SizedBox(height: 16),
          productList(context, ref, searchText),
        ],
      ),
    );
  }

  Widget productList(BuildContext context, WidgetRef ref, String searchText) {
    // 监听产品列表状态,状态变化自动刷新UI
    final productList = ref.watch(productListProvider);

    if (productList.isEmpty) {
      return const Center(child: Text("Nenhum produto encontrado"));
    }

    // 处理搜索过滤逻辑
    final filteredList = searchText.isEmpty
        ? productList
        : productList.where((p) => p.name.toLowerCase().contains(searchText.toLowerCase())).toList();

    return productListTile(filteredList, ref);
  }

  Widget productListTile(List<Product> productList, WidgetRef ref) {
    return ListView.builder(
      itemCount: productList.length,
      itemBuilder: (context, index) {
        final product = productList[index];
        return Slidable(
          endActionPane: ActionPane(
            motion: const ScrollMotion(),
            children: [
              SlidableAction(
                onPressed: (context) async {
                  // 调用StateNotifier的删除方法
                  await ref.read(productListProvider.notifier).deleteProduct(product.id!);
                },
                backgroundColor: Colors.red,
                foregroundColor: Colors.white,
                icon: Icons.delete,
                label: "Deletar",
              )
            ],
          ),
          child: ListTile(
            title: Text(product.name),
            subtitle: Text(product.brand ?? ''),
            trailing: Text(product.price.toStringAsFixed(2)),
          ),
        );
      },
    );
  }
}

关键优化点

  • 状态管理逻辑封装:用StateNotifier统一处理数据加载、删除逻辑,避免UI层直接操作状态和数据库,保证代码可维护性。
  • 触发状态更新的正确方式:每次更新状态时创建新的列表实例(state = state.where(...).toList()),让Riverpod能够检测到状态变化,自动通知UI刷新。
  • 直接监听状态:移除FutureBuilder,通过ref.watch(productListProvider)直接绑定状态,状态更新时UI自动重建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:42:02