The purpose of the go_router for Flutter is to use declarative routes to reduce complexity, regardless of the platform you're targeting (mobile, web, desktop), handling deep linking from Android, iOS and the web while still allowing an easy-to-use developer experience.
The simplest way to navigate to a page is Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyHomePage()));. I know there is some simple methods like If you are using getx then u can simply navigate using Get.to('MyHomePage()'). This is also fine. In both of the above methods we are using dart's typed_language_feature . We can define as many parameters as we can either required or optional. This way Dart enforces us to provide specific arguments it needs to build the widget.
But think about this:-
I have a UserForm that accepts an options argument of type User. If the User is null then it will create a new user else it will update the old user. So using go_router, I can define userForm route like this-
So you will see that it is not enforcing the routes to provide specific typed data. Here we loosing the type_language_feature of dart that is not a good practice.
Suppose that I have registered 100 routes and one of the route is
and we still need to provide extra and some queryParams then how can I remember how many params I am using for a specific route and especially the order of params. I can go to routes file and easily see what params and queryParams it is accepting but that is annoying.
How we can get rid of all these problems?
Here comes the source_gen package to rescue us. Here, I, for my own apps, build a TypedRoute class as
class TypedRoute {
final String path;
final Object? extra;
final Map<String, String>? queryParams;
TypedRoute._(this.path, this.extra, this.queryParams);
String get fullPath => queryParams == null ? path : Uri(path: path, queryParameters: queryParams).toString();
void push(BuildContext context) => GoRouter.of(context).push(fullPath, extra: extra);
void replace(BuildContext context) => GoRouter.of(context).go(fullPath, extra: extra);
}
then for each route, I create a relevent named constructor like this
I create TypedRoute class manually but this can be generated using code generation. To use code generation GoRoute and GoRouteState need to be changed slightly. GoRoute may be generic and GoRouteState.extra inference the type of object from GoRoute instead of hardcoded Object? like
GoRoute<User>(
// STEP 1 : Make GoRoute generic ex. class GoRoute<E extends Object> ...
path: '/userForm',
builder: (context, state) {
return UserForm(user: state.extra); // Step 2 : Type of GoRouteState.extra may be inferenced from GoRoute generic instead of Object?
}, //
)
Now parse the route , extract the params,and generate some relevant code. This way you can generate named constructors in TypedData class for each and every route.
This also simplifies this
GoRoute(
path: '/userForm',
builder: (context, state) {
// return UserForm(user: state.extra==null ? null : state.extra as User);
return UserForm(user: state.extra); // because the type is infered
},
),
This make code more maintainable, readable, and very importantly less prone to errors because here we are using dart's typed_language_feature again. 😎
I wish I can help you achieving this. But I can share TypedRouteClass for each and every scenario.
THANKS FOR READING IT CAREFULLY.
The simplest way to navigate to a page is
Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyHomePage()));
. I know there is some simple methods like If you are using getx then u can simply navigate usingGet.to('MyHomePage()')
. This is also fine. In both of the above methods we are using dart's typed_language_feature . We can define as many parameters as we can either required or optional. This way Dart enforces us to provide specific arguments it needs to build the widget. But think about this:-I have a
UserForm
that accepts an options argument of typeUser
. If theUser
is null then it will create a new user else it will update the old user. So using go_router, I can defineuserForm
route like this-and to navigate it I am using
This is not good, because I can also use
So you will see that it is not enforcing the routes to provide specific typed data. Here we loosing the
type_language_feature
of dart that is not a good practice. Suppose that I have registered 100 routes and one of the route isand we still need to provide
extra
and somequeryParams
then how can I remember how many params I am using for a specific route and especially the order ofparams
. I can go to routes file and easily see whatparams
andqueryParams
it is accepting but that is annoying.How we can get rid of all these problems?
Here comes the
source_gen
package to rescue us. Here, I, for my own apps, build aTypedRoute
class asthen for each route, I create a relevent named constructor like this
Now I can easily navigate using
I create TypedRoute class manually but this can be generated using code generation. To use code generation
GoRoute
andGoRouteState
need to be changed slightly.GoRoute
may be generic andGoRouteState.extra
inference the type of object fromGoRoute
instead of hardcodedObject?
likeNow parse the route , extract the params,and generate some relevant code. This way you can generate named constructors in TypedData class for each and every route.
This also simplifies this
This make code more maintainable, readable, and very importantly less prone to errors because here we are using dart's
typed_language_feature
again. 😎I wish I can help you achieving this. But I can share TypedRouteClass for each and every scenario. THANKS FOR READING IT CAREFULLY.