I have been trying to build an app using flutter and I am having a hard time figuring out certain concepts in flutter. I am hoping to find some answers here.
Preface: App dependencies: flutter_mobx,auto_route,get_it.
I am building an app where I need to show some alerts. I have created a Flutter page (AlertsScreen) which is subscribed to mobx alerts_store. So whenever I try to push an alert to the alerts_store the snackbar should popup. Something similar to which I have been doing in React web.
App repo link: https://github.com/ganeshrvel/open_cloud_encryptor/tree/new-router-logic
Questions:
AlertsScreen() which will be rendered across the app.
Earlier I used to do something like this: app.dart (Github link)
MaterialApp(
builder: (BuildContext context, Widget widget) {
setErrorBuilder();
return Column(
children: <Widget>[
Expanded(
child: widget,
),
AlertsScreen(),
],
);
},
title: 'App name',
onGenerateRoute: Router.onGenerateRoute,
initialRoute: Router.splashScreen,
navigatorKey: Router.navigator.key,
)
But then whenever I try to render Flushbar or any other item inside AlertsScreen which requires context it throws an error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Navigator operation requested with a context that does not include a Navigator. The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
Flushbar example code:
Flushbar(
title: 'title',
message: 'body',
duration: const Duration(seconds: 5),
).show(context);
How do I mount a common widget like AlertsScreen across the app and which will be always visible for any sort of activity?
2) This answer from stackoverflow suggests to make a CommonWidget stateless widget and use it wherever it has to be rendered. So taking cues from the above stackoverflow answer I modified my code like this:
common_widget.dart (Github link)
class CommonWidget extends StatelessWidget {
final Widget child;
const CommonWidget({
@required this.child,
});
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: child,
),
AlertsScreen(),
],
);
}
}
home.dart (Github link)
class _HomeScreenState extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: CommonWidget(
child: Center(
child: Column(),
),
),
);
}
}
Is this the right way to do it?
3) I use flutter_mobx as the store for AlertsScreen. Since I have used CommonWidget in multiple screens for displaying AlertsScreen, whenever I update the store the AlertsScreen gets rebuilt multiple time. How do I prevent this? How do I make sure that AlertsScreen widget is only rerendered in the current screen and prevent it from rebuilding everywhere else while updating the store?
Current the workaround is something like this:
alerts.dart (Github Link)
@override
void didChangeDependencies() {
super.didChangeDependencies();
_alertsStore ??= Provider.of<AlertsStore>(context);
_disposers ??= [
reaction(
(_) => _alertsStore.alertsList.iterator,
(alertsList) {
// Check whether current screen is rendered
if (ModalRoute.of(context).isCurrent) {
buildSnackbar();
}
},
),
];
}
Is there any better way to do this?