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

如何根据布尔值条件化使用不同的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:49:51