Bỏ qua để đến nội dung

🧭 GoRouter

GoRouter là package navigation hiện đại cho Flutter:

  • Type-safe routing
  • Deep linking support
  • Web URL support
  • Declarative API
pubspec.yaml
dependencies:
go_router: ^12.0.0

final router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/profile',
builder: (context, state) => ProfileScreen(),
),
GoRoute(
path: '/settings',
builder: (context, state) => SettingsScreen(),
),
],
);
MaterialApp.router(
routerConfig: router,
)

context.go('/profile');
context.push('/profile');
context.pop();
context.replace('/home');

Khác biệt giữa go, pushreplace:

1. context.go('/b')
Stack: [/a] ──▶ Stack: [/b] (Thay thế hoàn toàn stack cũ nếu cần)
2. context.push('/b')
Stack: [/a] ──▶ Stack: [/a, /b] (Thêm vào đỉnh stack)
3. context.replace('/b')
Stack: [/a] ──▶ Stack: [/b] (Thay thế route hiện tại)

GoRoute(
path: '/user/:id',
builder: (context, state) {
final userId = state.pathParameters['id']!;
return UserScreen(userId: userId);
},
),
// Navigate
context.go('/user/123');

GoRoute(
path: '/search',
builder: (context, state) {
final query = state.uri.queryParameters['q'] ?? '';
return SearchScreen(query: query);
},
),
// Navigate
context.go('/search?q=flutter');

Truyền object phức tạp:

// Navigate với extra
context.go('/product', extra: Product(id: 1, name: 'iPhone'));
// Nhận trong route
GoRoute(
path: '/product',
builder: (context, state) {
final product = state.extra as Product;
return ProductScreen(product: product);
},
),

GoRoute(
path: '/shop',
builder: (context, state) => ShopScreen(),
routes: [
GoRoute(
path: 'products', // /shop/products
builder: (context, state) => ProductsScreen(),
routes: [
GoRoute(
path: ':id', // /shop/products/123
builder: (context, state) {
final id = state.pathParameters['id']!;
return ProductDetailScreen(id: id);
},
),
],
),
GoRoute(
path: 'cart', // /shop/cart
builder: (context, state) => CartScreen(),
),
],
),

final router = GoRouter(
redirect: (context, state) {
final isLoggedIn = authService.isLoggedIn;
final isLoggingIn = state.matchedLocation == '/login';
if (!isLoggedIn && !isLoggingIn) {
return '/login'; // Redirect to login
}
if (isLoggedIn && isLoggingIn) {
return '/'; // Redirect to home
}
return null; // No redirect
},
routes: [...],
);

Bottom navigation bar persistent across routes:

ShellRoute(
builder: (context, state, child) {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
currentIndex: _calculateSelectedIndex(state),
onTap: (index) => _onItemTapped(index, context),
),
);
},
routes: [
GoRoute(path: '/', builder: (_, __) => HomeScreen()),
GoRoute(path: '/search', builder: (_, __) => SearchScreen()),
GoRoute(path: '/profile', builder: (_, __) => ProfileScreen()),
],
),

final router = GoRouter(
errorBuilder: (context, state) {
return Scaffold(
body: Center(
child: Text('Page not found: ${state.uri}'),
),
);
},
routes: [...],
);

class AppRouter {
static final router = GoRouter(
initialLocation: '/',
redirect: _guard,
errorBuilder: (context, state) => NotFoundScreen(),
routes: [
GoRoute(
path: '/login',
builder: (context, state) => LoginScreen(),
),
ShellRoute(
builder: (context, state, child) => MainShell(child: child),
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/products',
builder: (context, state) => ProductsScreen(),
routes: [
GoRoute(
path: ':id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return ProductDetailScreen(id: id);
},
),
],
),
GoRoute(
path: '/profile',
builder: (context, state) => ProfileScreen(),
),
],
),
],
);
static String? _guard(BuildContext context, GoRouterState state) {
final isLoggedIn = context.read<AuthProvider>().isLoggedIn;
if (!isLoggedIn && state.matchedLocation != '/login') {
return '/login';
}
return null;
}
}
// main.dart
void main() {
runApp(
MaterialApp.router(
routerConfig: AppRouter.router,
),
);
}

Method Mô tả
context.go() Navigate, thay thế stack
context.push() Navigate, thêm vào stack
context.pop() Quay lại
context.replace() Replace current route
Feature Mô tả
Path params /user/:id
Query params /search?q=...
Extra data Object phức tạp
Redirect Auth guards
ShellRoute Persistent UI