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

Flutter RiverPod中合并多个FutureProvider生成新Provider的实现方法

解决方案

你要做的是合并两个FutureProvider返回的AsyncValue状态,把加载、错误、成功三种状态透传到合并后的weatherProvider即可,具体实现如下:


核心逻辑说明

在Riverpod中使用ref.watch监听FutureProvider时,拿到的返回值是封装了加载、错误、数据三种状态的AsyncValue对象,不需要手动await异步请求,只需要把两个子Provider的状态做合并处理即可。


完整实现代码

修改你的weather_provider.dart中的weatherProvider部分:

final weatherProvider = FutureProvider<WeatherData>((ref) async {
  // 监听两个子Provider的状态
  final currentWeatherAsync = ref.watch(currentWeatherProvider);
  final oneCallWeatherAsync = ref.watch(oneCallWeatherProvider);

  // 任意子Provider加载中,合并后的Provider也保持加载状态
  if (currentWeatherAsync is AsyncLoading || oneCallWeatherAsync is AsyncLoading) {
    throw const AsyncLoading();
  }

  // 任意子Provider报错,透传错误和堆栈信息到上层
  if (currentWeatherAsync.hasError) {
    throw Error.throwWithStackTrace(
      currentWeatherAsync.error!, 
      currentWeatherAsync.stackTrace!
    );
  }
  if (oneCallWeatherAsync.hasError) {
    throw Error.throwWithStackTrace(
      oneCallWeatherAsync.error!, 
      oneCallWeatherAsync.stackTrace!
    );
  }

  // 两个子Provider都加载成功,返回合并后的WeatherData
  return WeatherData(
    oneCallWeatherData: oneCallWeatherAsync.requireValue,
    currentWeatherData: currentWeatherAsync.requireValue,
  );
});

更简洁的合并写法(适用于Riverpod 2.0+版本)

可以用官方提供的combine扩展方法快速合并两个AsyncValue,不需要手动判断状态:

final weatherProvider = FutureProvider<WeatherData>((ref) {
  final currentAsync = ref.watch(currentWeatherProvider);
  final oneCallAsync = ref.watch(oneCallWeatherProvider);

  // 合并两个AsyncValue的状态,都成功时执行合并逻辑
  return currentAsync
      .combine(oneCallAsync, (currentData, oneCallData) => WeatherData(
            oneCallWeatherData: oneCallData,
            currentWeatherData: currentData,
          ))
      .when(
        loading: () => throw const AsyncLoading(),
        error: (error, stackTrace) => Error.throwWithStackTrace(error, stackTrace),
        data: (weatherData) => weatherData,
      );
});

UI层调用示例

合并后的Provider用法和普通FutureProvider完全一致,直接调用.when处理三种状态即可:

Consumer(
  builder: (context, ref, child) {
    final weatherAsync = ref.watch(weatherProvider);
    return weatherAsync.when(
      loading: () => const CircularProgressIndicator(),
      error: (error, stackTrace) => Text('天气数据加载失败:$error'),
      data: (weatherData) {
        // 直接使用两份数据
        final currentTemp = weatherData.currentWeatherData.temperature;
        final dailyForecast = weatherData.oneCallWeatherData.dailyList;
        return Column(
          children: [
            Text('当前温度:${currentTemp}°C'),
            // 渲染每日预报列表
            ...dailyForecast.map((item) => Text('${item.date}:${item.tempRange}')),
          ],
        );
      },
    );
  },
)

注意事项

  • 该实现会并行请求两个接口,性能和直接用Future.wait的方式完全一致,没有额外损耗
  • 如果两个子Provider存在依赖关系(比如第二个接口需要第一个接口返回的地理位置参数),可以直接在子Provider内部通过ref.watch依赖另一个Provider即可,合并逻辑不需要修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 20:15:00