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});@overrideWidget 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 {@overrideSettingState build(String deviceId) {// ref.watch 返回的是 AsyncValue<DeviceItemModel>final deviceDetailAsync = ref.watch(deviceDetailProvider(deviceId));// 使用 .valueOrNull 从包装盒中提出最新的数据实体final device = deviceDetailAsync.valueOrNull;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 {@overridevoid 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();}
}