如何根据布尔值条件化使用不同的StateNotifierProvider?
解决方案:避免Riverpod Provider Dispose后复用的错误
错误根源
你遇到的Bad state: Tried to use ... after dispose was called错误,本质是会话模式切换时,之前被销毁的Provider实例被意外引用。当从创建/编辑模式切回会话模式时,overrideWith回调可能复用了已被dispose的sessionTemplateProvider实例(如果它是autoDispose类型,或所在ProviderScope已销毁),或是新创建的TemplateProvider销毁时影响了全局sessionTemplateProvider的引用。
最优实现方案
方案1:条件化ProviderScope(推荐)
直接根据isSession值渲染不同的ProviderScope,确保每次切换模式时都重新绑定有效Provider实例,彻底避免旧实例引用问题:
// 父组件中 Widget build(BuildContext context) { return isSession ? ProviderScope( overrides: [ templateProvider.overrideWith( (ref) => ref.read(sessionTemplateProvider.notifier), ), ], child: TemplateWidget(), ) : ProviderScope( overrides: [ templateProvider.overrideWith( (ref) => TemplateProvider(template: template, isSession: false), ), ], child: TemplateWidget(), ); }
关键注意点:
- 确保
sessionTemplateProvider是全局非autoDispose的Provider(定义在App级ProviderScope中),使其生命周期与App一致,不会被意外销毁。 - 每次模式切换都会重建ProviderScope,保证
templateProvider绑定的是当前有效的实例。
方案2:用代理Provider封装切换逻辑
如果不想拆分ProviderScope,可以创建顶层代理Provider,统一对外暴露TemplateNotifier实例,子组件只需依赖这个代理Provider,无需关心底层实现:
步骤1:定义基础Provider
// 全局会话模板Provider(非autoDispose,持久化状态) final sessionTemplateProvider = StateNotifierProvider<SessionTemplateProvider, SessionState>((ref) { return SessionTemplateProvider(); }); // 编辑模板的autoDispose family Provider(每次编辑新模板时创建实例,无监听时自动销毁) final editingTemplateProvider = StateNotifierProvider.autoDispose.family<TemplateProvider, Template>((ref, template) { return TemplateProvider(template: template, isSession: false); }); // 控制模式切换的StateProvider(若isSession为动态变化值) final isSessionProvider = StateProvider<bool>((ref) => false);
步骤2:创建代理Provider
final currentTemplateProvider = Provider<TemplateNotifier>((ref) { final isSession = ref.watch(isSessionProvider); if (isSession) { // 返回全局会话模板的notifier return ref.read(sessionTemplateProvider.notifier); } else { // 获取当前编辑模板,返回对应编辑模式notifier final currentTemplate = ref.watch(currentEditingTemplateProvider); return ref.read(editingTemplateProvider(currentTemplate)); } });
步骤3:子组件使用代理Provider
所有子组件直接依赖currentTemplateProvider,无需判断模式:
final templateNotifier = ref.watch(currentTemplateProvider);
为什么autoDispose无效?
你尝试的autoDispose未解决问题,是因为错误并非来自新创建的TemplateProvider销毁,而是会话模式下复用了已被销毁的sessionTemplateProvider实例。如果sessionTemplateProvider是autoDispose类型,当没有组件监听它时会被销毁,再次切换回会话模式时就会引用已dispose的实例。
内容的提问来源于stack exchange,提问作者user3923920
相关产品推荐
相关产品推荐

