Reputation: 935
I use flutter_bloc
for the state management and go_router
for navigation and routing in my app.
Here's a simple version of my router
:
class AppRouter {
AppRouter._();
static GoRouter router = GoRouter(
initialLocation: '/splash',
routes: [
GoRoute(
path: '/splash',
builder: (context, state) => const SplashPage(),
),
GoRoute(
path: '/login',
builder: (context, state) {
return BlocProvider(
create: (context) => RegistrationCubit(),
child: const LoginPage(),
);
},
routes: [
GoRoute(
path: 'loading',
pageBuilder: (context, state) {
assert(state.extra is RegistrationCubit);
return DialogPage(
barrierDismissible: false,
builder: (_) => BlocProvider.value(
value: state.extra as RegistrationCubit,
child: const LoadingDialog(),
),
);
},
),
GoRoute(
path: 'confirmAccount',
builder: (context, state) {
assert(state.extra is RegistrationCubit);
return BlocProvider.value(
value: state.extra as RegistrationCubit,
child: const ConfirmAccountPage(),
);
},
routes: [
GoRoute(
path: 'loading',
pageBuilder: (context, state) {
assert(state.extra is RegistrationCubit);
return DialogPage(
barrierDismissible: false,
builder: (_) => BlocProvider.value(
value: state.extra as RegistrationCubit,
child: const LoadingDialog(),
),
);
},
),
],
),
],
),
GoRoute(
path: '/home',
builder: (context, state) => const HomePage(),
),
],
);
}
Here's a visualization of my router:
When the app starts, it first shows a splash page, after that, it shows the login page. The login page is provided with a RegistrationCubit
to manage the registration state such as keeping track of email and password. I want to provide the RegistrationCubit
to only the routes where /login
is their top parent, which means I don't want to provide it to /splash
or /home
, thus I don't want to declare it at the top of the app.
Now if I want to go to the loading page from the login page, I can call context.go('/login/loading')
. I also want to have access to RegistrationCubit
in the loading page, but now I cannot access it because it is not provided at the top of the app. Searching online, I learned that I can achieve this by passing the RegistrationCubit
as a value of the extra
parameter like this: context.go('/login/loading', extra: context.read<RegistrationCubit>())
and then I can provide it to the loading page using BlocProvider.value
in its GoRoute
as you can see in the code above.
The same method applies for other routes as well, such as /login/confirmAccount
and /login/confirmAccount/loading
. But I face a problem. Let's say I got to the confirm account page by calling context.go('/login/confirmAccount', extra: context.read<RegistrationCubit>())
, and now from this page, I want to go to the loading page, so I call context.go('/login/confirmAccount/loading', extra: context.read<RegistrationCubit>())
. But this gives me an error which points to the following portion of the code above:
GoRoute(
path: 'confirmAccount',
builder: (context, state) {
assert(state.extra is RegistrationCubit);
return BlocProvider.value(
value: state.extra as RegistrationCubit,
child: const ConfirmAccountPage(),
);
},
The error points to the assert
line saying that state.extra
is not of type RegistrationCubit
which means we didn't pass it as extra
, and I think that's right, we passed it to the route on top of that, which is the loading page route.
In the Navigator 1.0
we could easily do that by:
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: context.read<RegistrationCubit>(),
child: SomePage(),
),
),
);
Now my question is how to provide a bloc
to any route. Maybe my approach is not the right one at all!
Upvotes: 1
Views: 75
Reputation: 1
You could try ShellRoute, above this all routes that need access to the bloc. As far as i have tried, it works, but the redirect method can´t access it.
Upvotes: 0