Using enhanced enums with go_router
Table of Contents
What are enhanced enums? ๐ค #
Enhanced enums are a great way to define a set of values that are known at compile time. They are similar to the enum type, but they can also have methods and properties.
The new enhanced enums are available since Dart 2.17
How to use enhanced enums ๐ฏ #
First, ensure your dart/flutter project is using at least Dart 2.17.0 in your pubspec.yaml
:
environment:
sdk: ">=2.17.0 <3.0.0"
Let’s start with a simple example. We want to define a set of routes for our app. We can do this by creating an enum:
enum AppRoutes {
login,
home,
settings,
}
Now that we have our enum, we can enhance it to define our routes, views, etc…
enum AppRoutes {
login('/login', LoginPage()),
home('/home', HomePage()),
settings('/settings', SettingsPage()); // Don't forget to add the semicolon here :)
const AppRoutes(
this.path,
this.view,
);
final String path;
final Widget view;
}
That’s it! Now our enum has a path and a view.
Combining enhanced enums with go_router ๐ #
Now that we have our enhanced enum, we can use it with go_router to define our routes.
Let’s first add the go_router
dependency to our pubspec.yaml
:
dependencies:
go_router: ^5.1.5
And now let’s create our router:
final router = GoRouter(
initialLocation: AppRoutes.login.path,
routes: [
GoRoute(
path: AppRoutes.login.path,
pageBuilder: (context, state) => MaterialPage<void>(
key: state.pageKey,
child: AppRoutes.login.view,
),
),
// ... same for home/settings using AppRoutes.x.path and x.home.view
],
);
This already looks much better than the previous version, where we had to define the routes and views manually:
final router = GoRouter(
initialLocation: '/login',
routes: [
GoRoute(
path: '/login',
pageBuilder: (context, state) => MaterialPage<void>(
key: state.pageKey,
child: LoginPage(),
),
),
// ...
);
Anyway, we can make this even better by adding a method to our enum so that we can get the route directly from the enum just by calling AppRoutes.routeX.route
:
enum AppRoutes {
// ...
GoRoute get route => GoRoute(
path: path,
pageBuilder: (context, state) => MaterialPage<void>(
key: state.pageKey,
child: view,
),
);
}
This will allow us to simplify our router:
final router = GoRouter(
initialLocation: AppRoutes.login.path,
routes: [
AppRoutes.login.route,
AppRoutes.home.route,
AppRoutes.settings.route,
],
);
I like it picasso! ๐จ
Adding our router ๐ง #
Now that we have our router, we can add it to our app by updating our MaterialApp widget with a .router()
constructor and adding a routerConfig
parameter:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Enums and Router demo',
routerConfig: router,
);
}
}
Now that we have our router, we can easily navigate to those known routes, let’s test it by adding a text button to the login page:
//...
TextButton(
onPressed: () => context.go(AppRoutes.home.path),
child: Text('Home'),
),
//...
We can even simplify this by adding another method to our enum:
enum AppRoutes {
// ...
void go(BuildContext context) => context.go(path);
// Additionall, we can add push and replace methods :)
void push(BuildContext context) => context.push(path);
void replace(BuildContext context) => context.replace(path);
}
And now we can easily navigate to our with the use of our new methods:
//...
TextButton(
onPressed: () => AppRoutes.home.go(context),
// onPressed: () => AppRoutes.home.push(context),
// onPressed: () => AppRoutes.home.replace(context),
child: Text('Home'),
),
//...
Now navigating seems much easier and less error-prone ๐
Conclusion ๐ #
In this post, I showed you how I like to use enhanced enums with go_router in order navigate in a more type-safe, less error-prone and in my opinion more readable way.
For sure there are some use cases where this approach might not be the best, but I think it’s worth trying it out and see if it fits your needs ๐
I hope you enjoyed it and that you found it useful.
If you have any questions or suggestions, feel free to leave a comment below. ๐
Thanks for reading! ๐ค
The full source code with 94.5% test coverage ๐งช for this post is available here ๐
Sorry, I couldn’t get it to 100% ๐
I don’t really know how to test the pageBuilder, but feel free to open a PR if you know how to do it ๐
The pubspec.yaml file for this project uses the following dependencies ๐ฆ
dependencies:
flutter:
sdk: flutter
go_router: ^5.1.5 # Used to define our router
dev_dependencies:
flutter_test:
sdk: flutter
very_good_analysis: ^3.1.0 # Used to enforce very good practices ๐ฆ