如何同时使用@freezed与@riverpod?遇ref未定义问题求解
问题解决思路及推荐方案
当前写法的核心问题
@freezed 生成的是纯数据模型类,它的本职就是封装状态数据,不该掺和依赖外部服务(比如SharedPreferences)的业务逻辑(像保存、读取这类操作)。而Riverpod的ref是Provider逻辑层的专属依赖,硬往数据类里塞肯定会出问题。
临时凑合用的解决方式(不推荐)
如果非要在现有结构里搞定,你可以把ref作为参数传入需要用到它的方法:
@freezed class Settings with _$Settings { const factory Settings({required bool darkMode}) = _Settings; // 把ref作为参数传给save方法 Future<void> save(WidgetRef ref) async { final prefs = await ref.watch(sharedPreferencesProvider.future); await prefs.setBool('dark_mode', darkMode); } // 从Provider里把ref传进来构建实例 factory Settings.fromPrefs(WidgetRef ref) { final prefs = ref.watch(sharedPreferencesProvider); return Settings(darkMode: prefs.getBool('dark_mode') ?? false); } } // 对应的Provider final settingsProvider = Provider<Settings>((ref) { return Settings.fromPrefs(ref); });
但这种写法太别扭了,等于把本该属于Provider的逻辑硬甩给数据类,违背了单一职责原则,只能临时救急,不能长期用。
更合理的拆分方案(强烈推荐)
正确的姿势是把数据模型和状态管理逻辑彻底分开:
- 用@freezed定义纯数据类,只负责存数据
- 用Riverpod的Notifier类(比如AsyncNotifier、StateNotifier)来封装读取、保存等业务逻辑,这里就能正常访问
ref
代码示例:
1. 纯数据模型(仅用@freezed)
@freezed class Settings with _$Settings { const factory Settings({required bool darkMode}) = _Settings; // 只保留和数据序列化相关的方法,比如从Map转模型 factory Settings.fromJson(Map<String, dynamic> json) => _$SettingsFromJson(json); }
2. 用Riverpod的AsyncNotifierProvider管理状态和逻辑
final settingsProvider = AsyncNotifierProvider<SettingsNotifier, Settings>(() { return SettingsNotifier(); }); class SettingsNotifier extends AsyncNotifier<Settings> { @override Future<Settings> build() async { // 这里可以正常访问ref,读取SharedPreferences final prefs = await ref.watch(sharedPreferencesProvider.future); final darkMode = prefs.getBool('dark_mode') ?? false; return Settings(darkMode: darkMode); } // 封装save方法,同样能访问ref Future<void> save(Settings newSettings) async { state = const AsyncValue.loading(); try { final prefs = await ref.watch(sharedPreferencesProvider.future); await prefs.setBool('dark_mode', newSettings.darkMode); state = AsyncValue.data(newSettings); } catch (e) { state = AsyncValue.error(e, StackTrace.current); } } }
这么拆分后,数据模型只管数据结构,状态管理逻辑全在Notifier里,既符合Freezed和Riverpod的设计初衷,代码也更清晰好维护。
内容的提问来源于stack exchange,提问作者psyched
相关产品推荐
相关产品推荐

