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

Flutter/Riverpod:如何优化FutureProvider的更新逻辑?

优化方案

1. 移除不必要的setState

原代码里用setState包裹ref.invalidate完全多余,Riverpod的ref操作本身会触发Provider重新计算,进而更新依赖该Provider的Widget。直接修改按钮点击逻辑即可:

onPressed: () {
  ref.invalidate(myFutureProvider);
},

2. 自动监听网络状态变化(替代手动重试)

把网络状态检测封装为独立的StreamProvider,让myFutureProvider依赖它,这样网络状态变化时会自动触发数据重新加载,无需手动点击按钮:

第一步:创建网络状态监听Provider

final connectivityProvider = StreamProvider<ConnectivityResult>((ref) {
  final connectivity = Connectivity();
  // 先获取当前网络状态,再监听后续变化
  return connectivity.onConnectivityChanged
      .startWith(connectivity.checkConnectivity());
});

第二步:修改myFutureProvider依赖网络状态Provider

final myFutureProvider = FutureProvider<ProductLoadResult<Data>>((ref) async {
  // 监听网络状态,状态变化时会重新执行该Provider
  final connectivityResult = await ref.watch(connectivityProvider.future);
  final netAvailable = connectivityResult != ConnectivityResult.none;

  if (netAvailable) {
    final productsApi = ref.read(productsApiProvider);
    final result = await productsApi.getData();
    return ProductLoadResult<Data>(true, result);
  } else {
    return ProductLoadResult<Data>(false, null);
  }
});

当网络从不可用变为可用时,myFutureProvider会自动重新发起API请求,无需手动操作。

3. 错误处理优化

原代码中API请求出错会直接进入error分支,可以在myFutureProvider内部捕获API错误,统一用ProductLoadResult返回,让UI处理更一致:

final myFutureProvider = FutureProvider<ProductLoadResult<Data>>((ref) async {
  final connectivityResult = await ref.watch(connectivityProvider.future);
  final netAvailable = connectivityResult != ConnectivityResult.none;

  if (netAvailable) {
    try {
      final productsApi = ref.read(productsApiProvider);
      final result = await productsApi.getData();
      return ProductLoadResult<Data>(true, result);
    } catch (e) {
      // 返回错误状态,UI可以统一处理
      return ProductLoadResult<Data>(false, null, error: e.toString());
    }
  } else {
    return ProductLoadResult<Data>(false, null);
  }
});

对应的ProductLoadResult新增错误字段:

class ProductLoadResult<T> {
  final bool hasData;
  final T? data;
  final String? error;

  ProductLoadResult(this.hasData, this.data, {this.error});
}

UI中data分支可以同时处理无网络和API错误的情况:

Widget _bodyForData(ProductLoadResult<Data> result) {
  if (!result.hasData) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(result.error ?? "网络不可用"),
          ElevatedButton(
            onPressed: () => ref.invalidate(myFutureProvider),
            child: const Text("重试"),
          ),
        ],
      ),
    );
  }
  // 渲染正常数据
  return ListView(/* ... */);
}

总结

  • 移除多余的setState,直接用ref.invalidate触发手动重试
  • 通过StreamProvider监听网络状态,实现自动重新加载
  • 统一错误处理逻辑,让UI状态更一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 23:48:17