I'm using a shell route setup in Flutter with go_router
where I have a HomePage
and a ProfilePage
. From HomePage
, I navigate to DetailsPage
using a button. My intention is to access HomeCubit
in DetailsPage
to perform a specific task. However, when I try to use context.read<HomeCubit>().task()
in DetailsPage
, I encounter a ProviderNotFoundException
.
The exact error message is:
Exception has occurred. ProviderNotFoundException (Error: Could not find the correct Provider above this DownloadParametersPage Widget
This happens because you used a
BuildContext
that does not include the provider of your choice. There are a few common scenarios:You added a new provider in your
main.dart
and performed a hot-reload. To fix, perform a hot-restart.The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
You used a
BuildContext
that is an ancestor of the provider you are trying to read.Make sure that DownloadParametersPage is under your MultiProvider/Provider. This usually happens when you are creating a provider and trying to read it immediately.
The error suggests that the BuildContext in DetailsPage
does not include HomeCubit
. I understand that providers in Flutter are scoped, and if a provider is inserted in one route, it might not be accessible in another. However, I'm not sure how to structure my code to make HomeCubit
available in DetailsPage
.
Here is the relevant part of my implementation using type-safe routes with go_router:
// Shell route with HomeRoute and ProfileRoute
@TypedShellRoute<MyShellRouteData>(
routes: <TypedRoute<RouteData>>[
TypedGoRoute<HomeRoute>(path: '/home', routes: [
TypedGoRoute<DetailsRoute>(path: 'details'),
]),
TypedGoRoute<ProfileRoute>(path: '/profile'),
],
)
class MyShellRouteData extends ShellRouteData {
// Implementation details...
}
// HomeRoute with BlocProvider for HomeCubit
@immutable
class HomeRoute extends GoRouteData {
@override
CustomTransitionPage<void> buildPage(BuildContext context, GoRouterState state) {
return CustomTransitionPage<void>(
key: state.pageKey,
child: BlocProvider<DiagnosesCubit>(
create: (context) => HomeCubit(),
child: const HomePage(),
),
// Transition details...
);
}
}
// DetailsRoute implementation
@immutable
class DetailsRoute extends GoRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const DetailsPage();
}
}
// ProfileRoute implementation
@immutable
class ProfileRoute extends GoRouteData {
// Implementation details...
}
I tried to read the go_router documentation but I didn't find any useful tips regarding this issue.
How can I structure my routes or modify my provider setup so that HomeCubit
is accessible in DetailsPage
?
Thank you in advance!
Hope I'm not late for this conversation!
In GoRouter, when you nest a route in another GoRouter.routes, the route is not nested the way we would think. The widgets are instantiate in a parallel way. Which means that their context are never nested. You can open devtools and inspect the widget tree and you will see this.
In order for DetailsPage to access your HomeCubit. You need to have a shared context in common. This can only be done by using ShellRoute.
I made a small package solving the issue of nested routes, so it works more fluently and without the need of this boilerplate. Take a look: https://pub.dev/packages/go_provider