🧭 GoRouter
1. Giới thiệu
Phần tiêu đề “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
dependencies: go_router: ^12.0.02. Setup cơ bản
Phần tiêu đề “2. Setup cơ bản”Định nghĩa Router
Phần tiêu đề “Đị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
Phần tiêu đề “Sử dụng trong MaterialApp”MaterialApp.router( routerConfig: router,)3. Navigate
Phần tiêu đề “3. Navigate”go - Navigate và replace stack
Phần tiêu đề “go - Navigate và replace stack”context.go('/profile');push - Add to stack
Phần tiêu đề “push - Add to stack”context.push('/profile');pop - Go back
Phần tiêu đề “pop - Go back”context.pop();replace - Replace current
Phần tiêu đề “replace - Replace current”context.replace('/home');Visualizing Navigation Stack
Phần tiêu đề “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
Phần tiêu đề “4. Path Parameters”GoRoute( path: '/user/:id', builder: (context, state) { final userId = state.pathParameters['id']!; return UserScreen(userId: userId); },),
// Navigatecontext.go('/user/123');5. Query Parameters
Phần tiêu đề “5. Query Parameters”GoRoute( path: '/search', builder: (context, state) { final query = state.uri.queryParameters['q'] ?? ''; return SearchScreen(query: query); },),
// Navigatecontext.go('/search?q=flutter');6. Extra Data
Phần tiêu đề “6. Extra Data”Truyền object phức tạp:
// Navigate với extracontext.go('/product', extra: Product(id: 1, name: 'iPhone'));
// Nhận trong routeGoRoute( path: '/product', builder: (context, state) { final product = state.extra as Product; return ProductScreen(product: product); },),7. Nested Routes
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “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 đủ
Phần tiêu đề “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.dartvoid main() { runApp( MaterialApp.router( routerConfig: AppRouter.router, ), );}📝 Tóm tắt
Phần tiêu đề “📝 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 |