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
相关产品推荐
相关产品推荐

