🗺️ Named Routes
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Named routes cho phép định nghĩa routes bằng tên thay vì tạo MaterialPageRoute mỗi lần:
Navigator.pushNamed(context, '/profile');2. Định nghĩa Routes
Phần tiêu đề “2. Định nghĩa Routes”Trong MaterialApp
Phần tiêu đề “Trong MaterialApp”MaterialApp( initialRoute: '/', routes: { '/': (context) => HomeScreen(), '/profile': (context) => ProfileScreen(), '/settings': (context) => SettingsScreen(), '/login': (context) => LoginScreen(), },)3. Navigate với Named Routes
Phần tiêu đề “3. Navigate với Named Routes”pushNamed
Phần tiêu đề “pushNamed”Navigator.pushNamed(context, '/profile');pushReplacementNamed
Phần tiêu đề “pushReplacementNamed”Navigator.pushReplacementNamed(context, '/home');pushNamedAndRemoveUntil
Phần tiêu đề “pushNamedAndRemoveUntil”Navigator.pushNamedAndRemoveUntil( context, '/home', (route) => false, // Xóa tất cả);popAndPushNamed
Phần tiêu đề “popAndPushNamed”Navigator.popAndPushNamed(context, '/profile');4. Truyền Arguments
Phần tiêu đề “4. Truyền Arguments”Gửi arguments
Phần tiêu đề “Gửi arguments”Navigator.pushNamed( context, '/profile', arguments: {'userId': 123, 'name': 'John'},);
// Hoặc với objectNavigator.pushNamed( context, '/profile', arguments: User(id: 123, name: 'John'),);Nhận arguments
Phần tiêu đề “Nhận arguments”class ProfileScreen extends StatelessWidget { @override Widget build(BuildContext context) { // Nhận arguments final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>; final userId = args['userId'];
// Hoặc với object // final user = ModalRoute.of(context)!.settings.arguments as User;
return Scaffold( appBar: AppBar(title: Text('User $userId')), ); }}5. onGenerateRoute - Dynamic Routes
Phần tiêu đề “5. onGenerateRoute - Dynamic Routes”Xử lý routes động với arguments:
MaterialApp( initialRoute: '/', onGenerateRoute: (settings) { switch (settings.name) { case '/': return MaterialPageRoute(builder: (_) => HomeScreen());
case '/profile': final args = settings.arguments as Map<String, dynamic>?; return MaterialPageRoute( builder: (_) => ProfileScreen(userId: args?['userId']), );
case '/product': final productId = settings.arguments as int; return MaterialPageRoute( builder: (_) => ProductScreen(productId: productId), );
default: return MaterialPageRoute(builder: (_) => NotFoundScreen()); } },)6. onUnknownRoute
Phần tiêu đề “6. onUnknownRoute”Xử lý route không tồn tại:
MaterialApp( onUnknownRoute: (settings) { return MaterialPageRoute( builder: (_) => NotFoundScreen(), ); },)7. Route Constants
Phần tiêu đề “7. Route Constants”Best practice: định nghĩa route names là constants:
class AppRoutes { static const home = '/'; static const login = '/login'; static const profile = '/profile'; static const settings = '/settings'; static const productDetail = '/product';}
// Sử dụngNavigator.pushNamed(context, AppRoutes.profile);8. Ví dụ thực tế
Phần tiêu đề “8. Ví dụ thực tế”Route Configuration
Phần tiêu đề “Route Configuration”class AppRouter { static const home = '/'; static const login = '/login'; static const profile = '/profile'; static const product = '/product';
static Route<dynamic> generateRoute(RouteSettings settings) { switch (settings.name) { case home: return MaterialPageRoute(builder: (_) => HomeScreen());
case login: return MaterialPageRoute(builder: (_) => LoginScreen());
case profile: final userId = settings.arguments as int?; return MaterialPageRoute( builder: (_) => ProfileScreen(userId: userId ?? 0), );
case product: final product = settings.arguments as Product; return MaterialPageRoute( builder: (_) => ProductDetailScreen(product: product), );
default: return MaterialPageRoute( builder: (_) => Scaffold( body: Center(child: Text('Route not found: ${settings.name}')), ), ); } }}
// main.dartMaterialApp( initialRoute: AppRouter.home, onGenerateRoute: AppRouter.generateRoute,)Navigation Helper
Phần tiêu đề “Navigation Helper”class NavigationService { static void goToProfile(BuildContext context, int userId) { Navigator.pushNamed(context, AppRoutes.profile, arguments: userId); }
static void goToProduct(BuildContext context, Product product) { Navigator.pushNamed(context, AppRoutes.product, arguments: product); }
static void logout(BuildContext context) { Navigator.pushNamedAndRemoveUntil( context, AppRoutes.login, (route) => false, ); }}9. Hạn chế của Named Routes
Phần tiêu đề “9. Hạn chế của Named Routes”- Không type-safe (arguments là dynamic)
- Khó refactor
- Không hỗ trợ deep linking tốt
💡 Khuyến nghị: Dùng GoRouter cho apps phức tạp (xem bài tiếp theo)
📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Method | Mô tả |
|---|---|
pushNamed |
Navigate đến named route |
pushReplacementNamed |
Replace với named route |
pushNamedAndRemoveUntil |
Push và xóa stack |
popAndPushNamed |
Pop và push named |
| Config | Mục đích |
|---|---|
routes |
Map tĩnh route → widget |
onGenerateRoute |
Dynamic route handling |
onUnknownRoute |
Route không tồn tại |