Thanks to visit codestin.com
Credit goes to towardsdev.com

Sitemap

Towards Dev

A publication for sharing projects, ideas, codes, and new theories.

Flutter Navigator 2.0 with GoRouter

Learn about the declarative routing mechanism in Flutter using the go_router package

8 min readJul 16, 2022

--

Press enter or click to view image in full size
Photo by Diego Jimenez on Unsplash

Navigation is a core concept in app development. Navigation refers to the interactions that allow users to navigate across, into, and back out from the different pieces of content within your app.

Table of Contents

What is GoRouter?

GoRouter is a declarative router for Flutter apps based on Navigation 2.0 to reduce complexity, regardless of the platform the app is running (mobile, web, or desktop), handle deep and dynamic linking, and data-driven routes while still providing an easy-to-use developer experience.

Now, What is Navigator 2.0?

The Navigator widget in Flutter is an imperative routing mechanism (Navigator 1.0), and Navigator 2.0 is the standard reference to declarative navigation and does not replace Navigator 1.0, as they can be used together. Navigator 2.0 offers a new declarative API design, Pages, for the existing Navigator widget. It also introduces a new Router widget.

  • Ah, now what is imperative and declarative?
  • Why bother about Navigator 2.0 when we already have a routing mechanism that works well and is easy?

This time, let’s start from the very depth. 📈

Imperative Programming is a programming paradigm that describes how a program will be executed. Developers are more concerned with the process of obtaining a solution step by step.

Whereas, Declarative Programming is a programming paradigm that expresses the logic of a computation without describing its control flow.

For example, Imperative Programming is like asking your friend how to solve a problem step by step. And Declarative Programming is like asking your friend to solve that problem, here you don’t care how he fixes the problem, you focus on the end result.

In Flutter, small applications are typically well served by simply using the Navigator API via the MaterialApp constructor’s MaterialApp.routes property.

But, more complex applications are generally served better by the Router API, which is accessible via the MaterialApp.router constructor. This takes a little more work upfront to describe how to parse deep links for your application and how to map the application state to the set of active pages, but it is more expressive in the long run.

Advantages of the Navigator 2.0

In Navigator 1.0, you can only add a page to the top of the navigation stack and remove the topmost route. The declarative mechanism, Navigator 2.0, on the other hand, gives you complete control over the navigation stack.

When the Web platform is targeted, parsing and restoring URLs add significant value to app navigation. The new API includes a component in charge of parsing URLs entered in the Web browser’s address bar and restoring URLs in the address bar as the application state changes.

How to implement the new Navigator technique?

Navigator 2.0 introduces Pages, a new declarative API design for the existing Navigator widget. It also adds a new Router widget. Customized RouterDelegate and RouteInformationParser classes are required for this new routing system. Both of these classes require a significant amount of effort to implement and will still leave you puzzled.

Some developers come up with their packages to make things a little bit easier and are made on top of the new declarative navigation mechanism - AutoRoute, Beamer, VRouter. All of these three have their strengths and weaknesses. For example, AutoRoute generally requires code generation. Beamer appeared exciting, but it’s a little bit ambiguous. Flutter developers were puzzled by VRouter’s similarly named APIs, which were used in different contexts.

There comes the go_router package with its intuitive and easy-to-use navigation approach. In this tutorial, we are going to see how to implement Navigator 2.0 using GoRouter and how it provides much more granular control for your app’s navigation.

Getting Started with GoRouter

In this tutorial, we are going to build a very simple application using GoRouter. The app will have three screens - LandingScreen which will be the initial screen, ColorExploreScreen which grids out a number of colored containers, and ColorShadeScreen which is responsible to list out different shades of a specific color based on an alpha value.

Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size

Get the Dependencies

In this project we require two dependencies:

  1. flutter_bloc: To work with a repository class. For this tutorial, making a repository class and creating a provider to manage it, wasn’t necessarily required. We could have done it in a different manner too. But good practices are good practices. Also, this makes our work a little bit easier, so we’ll make use of it.
  2. go_router: To reduce the complexity of the declarative routing mechanism.

Repository and Screens

Let’s create a repository class to hold a number of different colors, and also declare some helper methods. Check out the code below.

And create an instance of the repository using RepositoryProvider, as an ancestor widget of the MaterialApp.

There are three screens. Let’s discuss their routes or paths.

/ → will represent the LandingScreen() widget.

/colors → will represent the ColorExploreScreen() widget.

/colors/:index → will represent the ColorShadeScreen(index: index) widget with a specific color at index.

The last route may also contain some query parameters

/colors/:idx?alpha={alpha} → will represent the ColorShadeScreen(index: index, alpha: alpha) widget.

Now our job is to connect everything in such a way that whenever some interaction happens we call the necessary routes with the necessary parameters. And these parameters must be extracted by the widgets to show the proper result.

Initial setup for GoRouter

The go_router package has two main classes that you need to use - GoRouter and GoRoute. Creating a GoRouter constructor will give you a RouterDelegate, RouteInformationParser, and a RouteInformationProvider.

For routes, GoRouter uses a GoRoute that contains a path responsible for determining the URL, a builder that returns a page and a redirect handler that redirects to another route.

Error handling

GoRouter by default includes default error screens for both MaterialApp and CupertinoApp in addition to a default error screen if you’re not using either. You can set the errorBuilder parameter of the GoRouter to replace the default error screen.

Navigation

In order to navigate from one screen to another, there are a few ways of doing it. We can navigate using GoRouter or using the Dart extension method or using the Link widget.

Sub routes

Every top-level route will generate a single-page navigation stack in GoRouter. And sub-routes are used to create a navigation stack. Now check the below snippet carefully.

In the first case, / and /colors both are top-level routes. Whereas, in the second case, /colors is a sub-route of /. And there are two ways we can navigate to the /colors page from the home page. Either using context.go('/colors') or context.push('/colors'). So what is the difference between go and push?

Let’s take another example to understand the difference carefully.

See the /profile and /dashboard are the sub-routes of /user route. So if you are on the /user route it has started creating a navigation stack. When you navigate from /user to /profile route using context.go(‘/profile’) or context.push(‘/profile’), the profile route will be added on top of the users route as the profile is a sub-route of the user route. A similar thing happens when you navigate from /user to /dashboard route.

Go and Push works differently when you try to navigate from /profile to /dashboard route or vice versa. Let's say you are on the /profile route. So the navigation stack is made up with /user and /profile. Now if you do context.go(‘/dashboard’), it will jump to the target route /dashboard by removing the /profile route as /dashboard is not a sub-route of /profile.

But if you do context.push(‘/dashboard’) from the /profile route, it will push the target route into the already available navigation stack.

Parameters and Query Parameters

Both these terms are closely related but they are not the same at all, Parameters are set for the route, Query Parameters are values resembling variable assignment that provide extra information on what is being required for the route and it will always start with a ‘?’ on the URL, inherently they are both string values.

For example, from the route: creatures/:name

  • if we were to make a request to /creatures/alces, then alces is the name parameter.
  • if we were to make a request to /creatures/alces?familyName=Moose, then alces is the name parameter and Moose is the familyName query parameter.

Web history and neglect tracking

Every top-level route will create a navigation stack of one page. Sub-routes create an entire stack of pages so that it becomes easy to navigate to the previous or to the next page using arrow buttons in the browser. But sometimes, you may want to neglect to stack up pages.

For example, every time you change the alpha value it creates another page in our project. So if you want to go back to the explore screen via the back button, it will go through a number of screens. So let’s neglect to stack up pages when altering the alpha values.

If you want to know more and more in detail, check out the official documentation here at gorouter.dev.

The full source code for this application can be found here 👇

Conclusion

We now have a really good idea about Navigator 2.0 and how to implement using the go_router package. We have also experimented with its declarative routing, navigations, parameters, query parameters, and sub-routing.

Let’s celebrate then! 🎉

If you have any queries or suggestions or questions, dive into the comments sections. Alternatively, you can reach out to me using Instagram, Twitter, LinkedIn, or Email.

Please remember to applaud if this article was insightful and taught you something amazing. You know you can clap 50 times 🚀using that clap button. Give it a shot.😅

That’s it. Have a great day ahead!

--

--

Towards Dev
Towards Dev

Published in Towards Dev

A publication for sharing projects, ideas, codes, and new theories.

Sandip Pramanik
Sandip Pramanik

Written by Sandip Pramanik

Technical Content Creator | X (Formerly Twitter) - @thisissandipp

Responses (3)