Routing (GoRouter)
When to use
- •Adding a new screen or feature entry point.
- •Implementing deep linking or redirection (e.g., AuthGuard).
- •Passing arguments between screens.
Setup
Define a centralized local_router.dart (or similar) in core/router/ or app/router/.
Prefer nested/sub-routes over a flat list so deep links and back navigation remain predictable.
dart
final goRouter = GoRouter(
initialLocation: '/',
debugLogDiagnostics: true,
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomePage(),
routes: [
GoRoute(
path: 'details/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return DetailPage(id: id);
},
),
],
),
],
);
Best Practices
1) Type-Safe Arguments
- •Use path parameters for IDs (e.g.
details/:id). - •Use query parameters for filtering/sorting state (for example:
?status=paid&page=2). - •Use
extrafor complex objects only if necessary. Prefer passing an ID and refetching data to ensure the screen is independent and deep-linkable. - •Prefer typed routes or
goNamedover raw path strings where possible. - •Keep route path segments lowercase
kebab-case(for exampleuser/update-address).
2) Redirects (Guards)
- •implement
redirectlogic at the top level or per-route.
dart
redirect: (context, state) {
final isLoggedIn = authBloc.state.isAuthenticated;
final isLoggingIn = state.uri.path == '/login';
if (!isLoggedIn && !isLoggingIn) return '/login';
if (isLoggedIn && isLoggingIn) return '/';
return null;
},
3) Navigation
- •Use
context.go('/details/123')orcontext.goNamed(...)for normal app/deep-linkable navigation. - •Use
context.push('/details/123')when the route is transient and should return a result on pop. - •Prefer
BuildContextextensions (context.goNamed,context.pushNamed) overGoRouter.of(context)for consistency.