Named Routes
When you're navigating to a route with a location, you're hardcoding the URI construction into your app, e.g.
void _tap(BuildContext context, String fid, String pid) =>
context.go('/family/$fid/person/$pid');
Not only is that error-prone, but the actual URI format of your app could change over time. Certainly redirection helps keep old URI formats working, but do you really want various versions of your location URIs lying around willy-nilly in your code?
Navigating to Named Routes
The idea of named routes is to make it easy to navigate to a route w/o knowing
or caring what the URI format is. You can add a unique name to your route using
the GoRoute.name
parameter:
final _router = GoRouter(
routes: [
GoRoute(
name: 'home',
path: '/',
builder: ...,
routes: [
GoRoute(
name: 'family',
path: 'family/:fid',
builder: ...,
routes: [
GoRoute(
name: 'person',
path: 'person/:pid',
builder: ...,
),
],
),
],
),
GoRoute(
name: 'login',
path: '/login',
builder: ...,
),
],
You don't need to name any of your routes but the ones that you do name, you can navigate to using the name and whatever params are needed:
void _tap(BuildContext context, String fid, String pid) =>
context.go(context.namedLocation('person', params: {'fid': fid, 'pid': pid}));
The namedLocation
method will look up the route by name in a case-insensitive
way, construct the URI for you and fill in the params as appropriate. If you
miss a param or pass in params that aren't part of the path, you'll get an
error. Since it's somewhat inconvenient to have to dereference the context
object twice, go_router provides a goNamed
method that does the lookup and
navigation in one step:
void _tap(BuildContext context, String fid, String pid) =>
context.goNamed('person', params: {'fid': fid, 'pid': pid});
There is also a pushNamed
method that will look up the route by name, pull the
top page off of the generated match stack and push that onto the existing stack
of pages.
Redirecting to Named Routes
In addition to navigation, you may also want to be able to redirect to a named
route, which you can also do using the namedLocation
method of either
GoRouter
or GoRouterState
:
// redirect to the login page if the user is not logged in
redirect: (state) {
// if the user is not logged in, they need to login
final loggedIn = loginInfo.loggedIn;
final loginloc = state.namedLocation('login');
final loggingIn = state.subloc == loginloc;
// bundle the location the user is coming from into a query parameter
final homeloc = state.namedLocation('home');
final fromloc = state.subloc == homeloc ? '' : state.subloc;
if (!loggedIn) {
return loggingIn
? null
: state.namedLocation(
'login',
queryParams: {if (fromloc.isNotEmpty) 'from': fromloc},
);
}
// if the user is logged in, send them where they were going before (or
// home if they weren't going anywhere)
if (loggingIn) return state.queryParams['from'] ?? homeloc;
// no need to redirect at all
return null;
},
In this example, we're using namedLocation
to get the location for the named
'login' route and then comparing it to the current subloc
to find out if the
user is currently logging in or not. Furthermore, when we construct a location
for redirection, we use namedLocation
to pass in parameters to construct the
location. All of this is done without hardcoding any URI formatting into your
code.