惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
aimingoo的专栏
aimingoo的专栏
博客园 - 叶小钗
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
The Cloudflare Blog
S
SegmentFault 最新的问题
小众软件
小众软件
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
The GitHub Blog
The GitHub Blog
量子位
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
V2EX
Martin Fowler
Martin Fowler
博客园 - 【当耐特】
J
Java Code Geeks
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
Last Week in AI
Last Week in AI

博客园 - 水车

踩坑记录:Keyboard Maestro 截取 Chrome 浏览器窗口报错的终极避坑方案 2026 避坑首选:用专属域名发邮件的极致方案(Gmail + Cloudflare + Resend) Keyboard Maestro 逻辑控制深度指南:If Then Else 与多模态条件 Keyboard Maestro 进阶指南:如何像写代码一样调用宏(Macro) 深度解析 Keyboard Maestro 变量系统:从全局持久化到局部作用域 零门槛打造 4K 家庭影院:Mac mini M4 + 小米电视 + Jellyfin + Tailscale 全攻略 出墙记录 Mac 电脑用终端格式化移动硬盘/内存卡教程 IDEA中,如何切换Gemini Code Assist 登录的账号 Mac、Windows电脑怎么安装Java|JDK环境安装 Mac电脑设置chrome浏览器语言为英文办法 Mac 电脑安装Ruby新版本 Mac电脑:FVM4.x版本 安装教程 AWS S3服务,将当前桶设置成公开访问教程 Keyboard Maestro Tokens 使用方法 Chrome 下载文件时总是提示“已阻止不安全的下载”的解决方案 gin框架在BindJSON解析参数时,遇到错误直接返回400状态码的坑 Mac电脑下,关于Redis的一些使用记录 Mac电脑 docker 修改镜像源 ubuntu24 安装 caddy Ubuntu 24.04安装MySQL,并且配置外网访问
Riverpod3 注解方式写api 请求的provider在其他地方调用方式
水车 · 2026-07-23 · via 博客园 - 水车

在 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();
  }
}