bloc icon indicating copy to clipboard operation
bloc copied to clipboard

fix: BlocListeners fire for non-active pages that are still in the navigator stack

Open mattalbr opened this issue 6 months ago • 11 comments

Description IMO counter-intuitively, BlocListeners do not simply apply to the current route. Even after doing a Navigator.pushNamed, BlocListeners will continue to fire as long as the route that created them is somewhere in the Navigator stack.

This primarily (but not exclusively) comes up when using global blocs -- for us it's happened multiple times with our UserBloc that gets loaded both on initial login, and reloaded on various occasions. For example, the first page of our app with a sign in button has a BlocListener that waits for UserBloc to reach a logged in state and navigates to the next screen of our account creation flow. We then later reload the UserBloc after account creation is finished, which confusingly triggered the listener and re-navigated to the account creation flow.

Obviously there are ways for us to work around this specific issue, but from our perspective this is a huge footgun that has caused us multiple bugs in production, and is extremely challenging to debug. We're finally going to apply a big hammer and check in every BlocListener's listenWhen for (ModalRoute.of(context)?.isCurrent ?? false) but IMO this is something that should be handled by BlocListener itself.

This has come up in the past via https://github.com/felangel/bloc/issues/2255 and https://github.com/felangel/bloc/issues/2575 but from what I can tell, both of those bugs got closed after finding workarounds rather than addressing the core issue that this counter-intuitive behavior is bug prone and warrants re-consideration.

Steps To Reproduce

  1. Create an app with BlocListener<FooBloc, FooState>
  2. Call Navigator.pushNamed(Routes.bar)
  3. From Routes.bar, fire an event that pushes a new state to FooBloc's stream
  4. Observe that the original BlocListener fires again

Expected Behavior BlocListeners should only apply to the current page, i.e. when (ModalRoute.of(context)?.isCurrent ?? false) is true

mattalbr avatar Jul 31 '24 23:07 mattalbr