Routing Overview
Navigation is a crucial component of any app. A declarative routing structure is essential for building scalable apps that function seamlessly on both mobile and web platforms. At VGV, we recommend using the GoRouter package for handling navigation needs, as it provides a robust and flexible solution for managing routes.
GoRouter
GoRouter is a popular routing package that is maintained by the Flutter team. It is built on top of the Navigator 2.0 API and reduces much of the boilerplate code that is required for even simple navigation. It is a declarative routing package with a URL-based API that supports parsing path and query parameters, redirection, sub-routes, and multiple navigators. Additionally, GoRouter works well for both mobile and web apps.
Configuration
To enable deep linking in your app (such as redirecting to a login page or other features), routing must be carefully configured to properly support backwards navigation.
Structure your routes in a way that makes logical sense. Avoid placing all of your routes on the root path. Instead, use sub-routes.
Use type-safe routes
GoRouter allows you to define type-safe routes. When routes are type-safe, you no longer have to worry about typos and casting your route’s path and query parameters to the correct type.
Navigating to the categories
page using the type-safe route is as simple as calling:
Prefer go
over push
methods
GoRouter offers multiple ways to navigate to a route, such as pushing every route onto the stack and navigating to a route’s path.
When possible, use GoRouter’s go
methods for navigation. Calling go
pushes a new route onto the navigation stack according to your route’s path and updates the path in your browser’s URL address bar (if on web).
Use the push
method for navigation when you are expecting to receive data from a route when it is popped. Popping with data is a common scenario when pushing a dialog onto the stack which collects input from the user. Since you will never be expected to route the user directly to the dialog from a deep link, using push
prevents the address bar from updating the route.
Using go
will ensure that the back button in your app’s AppBar
will display when the current route has a parent that it can navigate backwards to. Root paths will not display a back button in their AppBar
. For example, /flutter/news
would display a back arrow in the AppBar
to navigate back to /flutter
, but /flutter
would not not display a back button. Using sub-routes correctly removes the need to manually handle the back button functionality.
Use hyphens for separating words in a URL
Mobile app users will likely never see your route’s path, but web app users can easily view it in the browser’s URL address bar. Your routing structure should be consistent and defined with the web in mind. Not only does this make your paths easier to read, it allows you the option of deploying your mobile app to the web without any routing changes needed.
Prefer navigating by name over path
If you’re using GoRoute’s type-safe routes, navigate using the go
extension method that was generated for your route.
If a route to a page is given to you from an external source, such as a push notification, to deep link to a specific page within your app, GoRouter allows you to navigate to a route by its name or by its path.
Because your app’s structure and paths can change over time, we recommend routing by name to avoid potential issues of a route’s path getting out of sync.
Consider this situation: An app has a route defined with the path /flutter-news
for the FlutterNewsPage
.
Later, the pages in the app were reorganized and the path to the FlutterNewsPage
has changed.
If the app was relying on the path
to navigate the user to the FlutterNewsPage
and the deep link path from the external source didn’t match the route’s path, the route would not be found. However, when relying on the route name
, navigation would work in either situation.
Extension methods
GoRouter provides extension methods on BuildContext
to simplify navigation. For consistency, use the extension method over the longer GoRouter
methods since they are functionally equivalent.
Navigating with parameters
Many times when navigating, you need to pass data from one page to another. GoRouter makes this easy by providing multiple ways to accomplish this: path parameters, query parameters, and an extra parameter.
Path parameters
Use path parameters when identifying a specific resource.
To navigate to the details page of a particular article, the GoRoute
would look like this:
Navigating to that page with the article id is as simple as providing the article id to the FlutterArticlePageRoute
’s constructor:
Query parameters
Use query parameters when filtering or sorting resources.
To navigate to a page of filtered articles, the GoRoute
would look like this:
To navigate to the list of filtered articles:
Extra parameter
GoRouter has the ability to pass objects from one page to another. Most of the time, however, we avoid using the extra
object when navigating to a new route.
In this example, we are passing the article
object to the article details page. If your app is designed to only work on mobile and there are no plans of deep linking to the articles details page, then this is fine. But, if the requirements change and now you want to support the web or deep link users directly to the details of a particular article, changes will need to be made. Instead, pass the identifier of the article as a path parameter and fetch the article information from inside of your article details page.
Redirects
Sometimes you need to redirect users to a different location in the app. For example: only signed-in users can access parts of your app. If the user isn’t signed-in, you want to redirect the user to the sign in page. Fortunately, GoRouter makes this very easy and redirects can be done at the root and sub-route level.
In this example, the user is redirected to the restricted
page if the user’s status isn’t premium
and tries to access /premium
, /premium/show
, or /premium/merch
. Having shows
and merch
as sub-routes avoids having to add redirect logic to each route.