GoRouter - Declarative Navigation
1. Giới thiệu
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.02. Setup cơ bản
Định nghĩa Router
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(),
),
],
);Sử dụng trong MaterialApp
MaterialApp.router(
routerConfig: router,
)3. Navigate
go - Navigate và replace stack
context.go('/profile');push - Add to stack
context.push('/profile');pop - Go back
context.pop();replace - Replace current
context.replace('/home');Visualizing Navigation Stack
Khác biệt giữa go, push và replace:
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)4. Path Parameters
GoRoute(
path: '/user/:id',
builder: (context, state) {
final userId = state.pathParameters['id']!;
return UserScreen(userId: userId);
},
),
// Navigate
context.go('/user/123');5. Query Parameters
GoRoute(
path: '/search',
builder: (context, state) {
final query = state.uri.queryParameters['q'] ?? '';
return SearchScreen(query: query);
},
),
// Navigate
context.go('/search?q=flutter');6. Extra Data
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);
},
),7. Nested Routes
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(),
),
],
),8. Redirect - Auth Guard
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: [...],
);9. ShellRoute - Persistent UI
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()),
],
),10. Error Handling
final router = GoRouter(
errorBuilder: (context, state) {
return Scaffold(
body: Center(
child: Text('Page not found: ${state.uri}'),
),
);
},
routes: [...],
);11. Ví dụ đầy đủ
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,
),
);
}📝 Tóm tắt
| 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 |
Last updated on