Reputation: 7954
My app uses FlutterBloc for state management. My use case:
My code to show details page on list item tap:
return GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => BlocProvider(
create: (_) => DetailsBloc(
someRepository: context.read<SomeRepository>(),
otherRepository context.read<OtherRepository>(),
)..add(GetItemDetailsEvent(id: item.id.toString())),
child: const EventDetailsPage(),
),
),
);
},
child: Card(....)
It works fine. On each list item tap, it shows new page and provides new DetailsBloc
instance to its context. After page is closed, bloc will be destroyed as well (this is how I want it to work). DetailsBloc
includes event to load details data by item id, so details window is able to refresh itself to show details.
But I prefer to use named routes and use pushNamed
instead. I am able to provide new DetailsBloc
instance this way when route is created and optionally, send event to it:
'/item_details': (context) => BlocProvider(
create: (context) => DataBloc(
someRepository: SomeRepository(),
otherRepository: OherRepository(),
)..add(GetItemDetailsEvent(id: <id>),
,
child: const DetailsPage()),
This way, I can show new page by Navigator.of(context).pushNamed('/item_details');
But in this case, I see no way to pass id to event to load data, because it's not known when route initialises itself. So I can't add event in route definition. I could try to add event later, on list item tap:
onTap: () {
context.read<DetailsBloc>().add((GetItemDetailsEvent(id: item.id.toString());
This obviously won't work, because DetailsBloc
is not provided here and it even does not exist anywhere before route is created. I can also add event to DetailsBloc
inside my DetailsPage
but it must be done in inside init state, so:
Do you have any ideas how to use named route here?
Upvotes: 1
Views: 416
Reputation: 2541
You could pass the id in router arguments:
await Navigator.pushNamed(
context,
DetailsPage.routeName,
arguments: id,
);
then in the route_builder:
...
case DetailsPage.routeName:
final arguments = settings.arguments as String;
return MaterialPageRoute(
builder: (context) => DetailsPage(itemId: arguments),
settings: settings,
);
...
and finaly in the DetailsPage:
class DetailsPage extends StatelessWidget {
const DetailsPage({
required this.itemId,
super.key,
});
static const routeName = '/details_page';
final int storyId;
@override
Widget build(BuildContext context) => BlocProvider<DetailsBloc>(
create: (context) => DetailsBloc(
someRepository: SomeRepository(),//or get it from DI or ServiceLocator
otherRepository: OtherRepository(),//or get it from DI or ServiceLocator
)..add(GetItemDetailsEvent(id: item.id.toString())),
child: const DetailsPageView(),
);
}
Upvotes: 1