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

使用BlocListener搭配Navigator.pushNamed出现导航栈页面重复问题

Bloc Listener导航栈重复问题解决方案

问题根源

你所有页面共享了同一个全局FieldsBloc实例,且所有页面的BlocConsumer都在监听同一个bloc的状态。当你在顶层页面触发事件emitFieldSuccessfulState时,所有还留在导航栈中的历史页面的listener都会被同时触发,每个listener都会执行一次pushNamed操作,最终导致导航栈重复插入多个页面。

另外你当前所有页面的listener都写死跳转到ExpertisePage.routeName,也不符合多页面依次跳转的逻辑,每个页面需要配置对应自己的下一级跳转目标。

解决方案

方案1:增加页面激活状态判断(快速修复)

在每个页面的listener中先判断当前页面是否为导航栈顶层的激活页面,只有激活页面才执行跳转逻辑,修改后的listener代码如下:

listener: (context, state) {
  if (state is FieldSuccessfulState) {
    // 仅当前页面处于顶层激活状态时才执行跳转
    if (ModalRoute.of(context)?.isCurrent != true) return;
    SchedulerBinding.instance.addPostFrameCallback((_) {
      // 替换为当前页面对应的目标路由,不要所有页面写死同一个跳转目标
      Navigator.of(context).pushNamed(ExpertisePage.routeName);
    });
  }
}

方案2:给状态增加触发标识+使用listenWhen过滤(规范实现)

  1. 修改FieldSuccessfulState增加触发页面标识字段:
class FieldSuccessfulState extends FieldsState {
  var data;
  // 标识触发该状态的页面路由名
  final String triggerRoute;
  FieldSuccessfulState(this.triggerRoute, [this.data]);
}
  1. Bloc中emit成功状态时传入当前触发事件对应的页面路由名:
// 示例:处理Category页的跳转事件时,传入CategoryPage的路由名
yield FieldSuccessfulState(CategoryPage.routeName);
  1. 每个页面的BlocConsumer增加listenWhen参数提前过滤状态,避免无效触发:
BlocConsumer<FieldsBloc, FieldsState>(
  listenWhen: (prev, current) {
    // 同时满足:当前页面激活、状态为成功状态、状态是当前页面触发的
    final isCurrent = ModalRoute.of(context)?.isCurrent ?? false;
    return isCurrent 
        && current is FieldSuccessfulState 
        && current.triggerRoute == CategoryPage.routeName;
  },
  listener: (context, state) {
    if (state is FieldSuccessfulState) {
      SchedulerBinding.instance.addPostFrameCallback((_) {
        Navigator.of(context).pushNamed(ExpertisePage.routeName);
      });
    }
  },
  builder: (context, state) {
    // 原有builder逻辑保持不变
  }
)

内容的提问来源于stack exchange,提问作者Hammas Ali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 06:54:03