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

Riverpod 2.0中FutureProvider正确用法:单次加载JSON字典

两种Riverpod 2.0加载字典方式对比与疑问解答

核心疑问:方式二会重复加载字典吗?

不会重复加载。Riverpod通过@riverpod生成的函数式Provider默认会缓存异步结果,只要Provider未被销毁,多次调用ref.watch()只会返回已缓存的Future,不会重新执行加载解析逻辑。只有手动调用ref.invalidate()触发刷新,或者Provider因无监听者被系统回收时,才会重新执行加载流程。

两种实现方式优劣对比

方式一:带keepAlive: true的类Provider

优势:

  • 显式设置keepAlive: true,确保Provider在整个应用生命周期内保持存活,完全契合“仅加载一次”的需求,不会因监听者消失被意外回收。
  • 类结构天然支持扩展,后续如果需要添加字典刷新、数据修改等功能,直接在类中新增方法即可,封装性更强。
  • 内置AsyncValue状态管理,调用ref.watch()时直接拿到包含加载、错误、成功状态的对象,像你在初始页面中处理加载状态那样,代码逻辑更直观。

不足:

  • 相比方式二,代码结构稍复杂,冗余代码略多。

方式二:函数式Provider

优势:

  • 代码极度简洁,逻辑直接,适合不需要后续扩展的简单场景。
  • 默认支持结果缓存,只要有监听者存在,就不会重复加载。

不足:

  • 扩展性差,后续若要添加刷新、修改等功能,不如类Provider方便。
  • 未显式设置存活策略,若所有监听者都被销毁(比如用户退出所有使用字典的页面),Provider会被回收,再次监听时会重新加载字典。如果要实现“仅加载一次”,需要手动添加ref.keepAlive():
    @riverpod
    Future<List<DictionaryEntry>> loadDictionary(LoadDictionaryRef ref) async {
      // 强制保持Provider存活,即使无监听者
      ref.keepAlive();
      try {
        final response = await rootBundle.loadString('assets/dict.json');
        final data = await json.decode(response) as List<dynamic>;
        final parsedData = data
            .map((e) => DictionaryEntry.fromMap(e as Map<String, dynamic>))
            .toList();
    
        return parsedData;
      } catch (e) {
        print(e);
        rethrow;
      }
    }
    

哪种方式更优?

如果需求是一次性加载字典,后续无修改或刷新需求,两种方式都能满足,但更推荐方式一:

  • 显式的keepAlive: true更贴合“仅加载一次”的语义,避免因作用域问题导致意外重新加载。
  • 类Provider的扩展性更强,后续需求变动时改动成本更低。
  • 内置的状态处理逻辑更便捷,代码可读性更高。

若追求极致简洁,且能确保Provider始终有监听者不会被回收,方式二也可使用,但务必加上ref.keepAlive()保证只加载一次。

内容的提问来源于stack exchange,提问作者José Carlos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:52:52