Flutter app navigation state and menu pattern using BLoC

Snir David
Flutter Community
Published in
3 min readJan 31, 2020

Navigation patterns for flutter are hard. And this is a scenario I stumbled upon and couldn’t find an agreed upon pattern to handle, so I made up one.

The scenario is this: You want to navigate to some “Views” of the app, and keep track of the current “View” for usage on some widget outside that view.

In my case, it was the BottomNavigatonVar that needs to constantly have its currentIndex parameter updated to the correct menu item we are viewing.

BottomNavigationBar with `currentIndex` set to 0, to mark `Home`

To solve this, we have 3 issues to tackle:

  1. Set a central place for the currentView state.
  2. Update the currentView state whenever navigating to a new “View”.
  3. Update the currentView state whenever user hit “back” (Which is not active navigation, as the widget will not rebuild).

State management

For a central place for the state, I chose to use BLoC provider, that will wrap my entire application.

As changing the currentView state will probably happen all around the app, we need something better than simple StatefulWidget . I chose BLoC, but really, Provider, RXDart or whatever is your favorite state management will work.

Updating state when navigating to new “View”

In my opinion the routing functions are the best place to update the currentView state. That way, you guarantee to have it happen when a routing is actively occurring.

Updating the state in other places, for example, when the “View” widget is building, is prone to bugs as the widget might rebuild even without new routing occurring.

Updating state when user goes back (navigation pop)

We need to “go back” a state whenever the user hits “back”. For that we will use the WillPopScope widget wrapping our app. Using onWillPop parameter to update the state accordingly.

Data structure for the history

We want to keep track of the history as a whole, for pushing new routes and being able to pop and go back to old routes state.

That calls for a stack. Unsurprisingly, if you will look at Navigator implementation you’ll see they use _historystack (implemented through List) internally exactly for this purpose.

Our implementation will be similar, but limited to our scope. Instead of logging all route changes, we will log only those we care about and in format easy for us.

Show me the code

The bloc class

Several things to address here:

  • The event enum is an enum that list the possible routes and additional special event go_back that speaks for itself.
  • Having this enum separated from the routes code itself is an advantage, as it allows more flexibility for whatever usage you need. For example, having multiple app routes map to a single “View” enum.
  • The event handling is pretty basic for readability. But this is the place to add code that will reject adding what is already the current route to the history, if that’s something you need.

Routing to a new route

Within the routing, we want to issue a bloc event for the appropriate view. that will look like this:

BlocProvider.of<CurrentViewBloc>(context).add(ViewOptions.home);

Say you are using fluro for navigation in your app, that means having this as the first step of the handlerFunc. Like this:

Initializing the bloc, routing back handling

We need to initialize the bloc state, and coincidentally here I also take care of the route pop case.

This should wrap the part of the app that is relevant for this routing. It can be on top of the entire application if your case necessitates that.

Thats it.

Pretty basic, but there are some tricks here that are nice to have in one place — using onWillPop , replicate a local history stack (I spent some time thinking Navigation reveals something like that, and that would have been a better way. But they don’t, _history is private) etc’ etc’.
Hope it has been useful for you.

--

--