Navigation with go_router
Learning objectives
- You know how to create and use routes with parameters.
Routing with go_router
One Flutter package that provides the possibility to parameterize routes is go_router. Here, in the present versions of the material, we are using the version 10.1.2 of it. While starting to use go_router
in local development requires adding it to the project dependencies outlined in pubspec.yaml
, we'll still continue working directly in the browser environment.
With go_router, we can create parameterized routes as shown in the following example. follows.
Let's look into the example in more detail.
Importing go_router and defining routes
The command import 'package:go_router/go_router.dart';
imports go_router
, loading its classes and allowing their use in the source code. We primarily use two classes: GoRouter and GoRoute.
The class GoRouter
is used for defining a top-level collection of routes for the application. GoRouter
takes a list of GoRoute objects as an argument, given to the routes
property. Each GoRoute
has a path
that corresponds to the route, e.g. /
, and a builder
that is used to create the shown screen.
The list of routes given to GoRouter
must include a root path, defined with /
, which is used as the starting path of the application. The following example outlines a simple routing, where the application shows an instantiation of a widget HomeScreen
.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
final router = GoRouter(
routes: [
GoRoute(path: '/', builder: (context, state) => HomeScreen()),
],
);
Defining path variables
Paths defined using GoRoute
can also contain path variables, denoted with a semicolon and a name for the variable (e.g. :id
). Path variables capture the value given to the variable, which is then passed to pathParameters
object that is a part of a state
object that is available for building the screen.
In the following example, accessing paths like /secrets/1
, /secrets/super
, and /secrets/fun
would all be lead to an attempt of showing an instance of a SecretScreen
.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
final router = GoRouter(
routes: [
GoRoute(path: '/', builder: (context, state) => HomeScreen()),
GoRoute(
path: '/secrets/:id',
builder: (context, state) =>
SecretScreen(int.parse(state.pathParameters['id']!))),
],
);
The pathParameters
property of state
contains a mapping from strings to strings.
To access a path variable, say :id
, we call state.pathParameters['id']!
, which returns a string corresponding to the path variable :id
. Tthe exclamation mark !
is used to denote that we claim that the variable exists.
In the above example, we also use the int.parse
function to transform the string into an integer, believing that the values given to the path are always integers. This may not always be the case, however.
Using routes
Routes are taken into use by passing a GoRouter
object as a parameter to the property routerConfig
of the MaterialApp.router named constructor.
final router = GoRouter(
routes: [
/* GoRoute-objects */
],
);
runApp(MaterialApp.router(routerConfig: router));
This creates an application with the given routes.
Navigating between routes
When creating an application with go_router
, an additional method go
is added to the BuildContext
. This method allows navigating at ease with calls such as context.go('/')
, context.go('/secrets/1')
, and so on.
In our application, the HomeScreen
had two buttons, each with their specific events leading to a secret screen. Similarly, the SecretScreen
had a button that led back to the home screen.
class HomeScreen extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(children: [
TextButton(
onPressed: () => context.go("/secrets/1"),
child: const Text("Show secret 1"),
),
TextButton(
onPressed: () => context.go("/secrets/2"),
child: const Text("Show secret 2"),
)
])));
}
}
class SecretScreen extends StatelessWidget {
final int secret;
const SecretScreen(this.secret);
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(children: [
Text("The secret is: $secret"),
TextButton(
onPressed: () => context.go("/"),
child: const Text("Hide secret"),
)
])));
}
}