加载中...

Riverpod3 注解方式写api 请求的provider在其他地方调用方式

在 View (UI 页面) 中的使用方式

在 UI 中,你可以直接使用 ref.watch 拿到的 AsyncValue。AsyncValue 提供了强大的 .when() 模式匹配,让你非常优雅地处理 Loading、Error 和 Data 状态。

class DeviceDetailView extends ConsumerWidget {
  final String deviceId;
  const DeviceDetailView({super.key, required this.deviceId});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 1. 获取异步状态 AsyncValue<DeviceItemModel>
    final deviceDetailAsync = ref.watch(deviceDetailProvider(deviceId));
    
    // 2. 获取 Notifier 实例(用来调用 updateName、refresh 等逻辑方法)
    final notifier = ref.read(deviceDetailProvider(deviceId).notifier);

    return Scaffold(
      // 3. 使用 .when 响应不同加载阶段
      body: deviceDetailAsync.when(
        // 数据加载成功
        data: (device) => Column(
          children: [
            Text('设备名称: ${device.deviceName}'),
            Text('在线状态: ${device.isOnline ? '在线' : '离线'}'),
            ElevatedButton(
              onPressed: () => notifier.updateName('新设备名字'),
              child: const Text('修改名称'),
            ),
          ],
        ),
        // 正在加载中(骨架屏/转圈)
        loading: () => const Center(child: CircularProgressIndicator()),
        // 加载报错
        error: (err, stack) => Center(
          child: Text('加载失败: $err'),
        ),
      ),
    );
  }
}

在其他 Provider 中的使用方式

在其他的 Notifier 或 Provider 内部使用时,主要分为 3 种典型场景:

场景 A:只想“监听”数据变化并同步(最常用)

如果你在另一个 Provider 中需要感知 api 的变更(例如设备名字变了,设置页也要跟着刷新); 当前方式不会阻塞UI渲染

@riverpod
class Setting extends _$Setting {
  @override
  SettingState build(String deviceId) {
    // ref.watch 返回的是 AsyncValue<DeviceItemModel>
    final deviceDetailAsync = ref.watch(deviceDetailProvider(deviceId));

    // 使用 .value 从包装盒中提出最新的数据实体,可能为null
    final device = deviceDetailAsync.value;

    return SettingState(
      deviceName: device?.deviceName ?? '默认名称',
      isOnline: device?.isOnline ?? false,
    );
  }
}

场景 B:异步链式依赖(等待它彻底加载完成后再做下一步)

如果你在当前 Provider 中需要严格等待 DeviceDetail 从网络/接口加载出来,再发起自己的请求:

@riverpod
Future<List<CameraStream>> cameraStreams(Ref ref, String deviceId) async {
  // 🌟 使用 .future!它会返回真正的 Future<DeviceItemModel>
  // 会一直 await 阻塞直到 DeviceDetail 的 build() 真正返回成功数据
  final device = await ref.watch(deviceDetailProvider(deviceId).future);

  // 拿到真正的 device 实体后,再发起属于自己的请求
  final streams = await fetchStreamsBySn(device.snNumber);
  return streams;
}

场景 C:在某个 Action(方法/按钮点击)中临时触发读取

如果不是在 build 阶段,而是在某个点击方法内部去主动触发或读取最新的设备数据

@riverpod
class ActionController extends _$ActionController {
  @override
  void build() {}

  Future<void> handleSomeClick(String deviceId) async {
    // 方式 1:如果确定只需要当前内存里已有的值
    final currentDevice = ref.read(deviceDetailProvider(deviceId)).valueOrNull;
    
    // 方式 2:如果不确定数据是否已加载完成,想确保拿到最新的(未完成就等待请求完成)
    final latestDevice = await ref.read(deviceDetailProvider(deviceId).future);

    // 方式 3:直接调用 DeviceDetail 的方法(如刷新)
    await ref.read(deviceDetailProvider(deviceId).notifier).refresh();
  }
}
posted @ 2026-07-23 17:54  水车  阅读(1)  评论(0)    收藏  举报