I have an application that uses Flutter-Redux. On certain user actions various redux-actions are dispatched and those run asynchronously in a middleware. My question now is:
redux is a bit clunky when it comes to "one-time errors". In general there are 2 ways to handle it:
I'm not sure how exactly your middleware looks like, but after the network request failed, you would push the error object into a rxdart Subject
or StreamController
. Now you have a Stream
of errors.
As a direct child of your StoreProvider
, create your own InheritedWidget
that holds the stream of errors, named SyncErrorProvider
:
class SyncErrorProvider extends InheritedWidget {
const SyncErrorProvider({Key key, this.errors, @required Widget child})
: assert(child != null),
super(key: key, child: child);
final Stream
The inherited widget should wrap your MaterialApp
. Now you have a simple way to access the stream of errors from any route, using SyncErrorProvider.of(context).errors
from didChangeDependencies
.
Displaying the error in a snackbar is a bit of a challenge, because the position of a snackbar depends on the page layout (FAB, bottom navigation...), and sometimes an appearing snackbar moves other UI elements.
The best way to handle the snackbar creation really depends on your app. I'm also not sure how often these errors would occur, so maybe don't spend too much time on it.
Two different approaches with advantages and disadvantages:
In every screen that has a scaffold, listen to the stream of errors and display snackbars in the local scaffold. Make sure to unsubscribe when the widgets are disposed.
Advantage of this approach is that the snackbars are a part of the page UI and will move other elements of the scaffold.
Disadvantage is that if there are dialogs or screens without a scaffold, the error will not be visible.
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
StreamSubscription _errorsSubscription;
final _scaffoldKey = GlobalKey();
@override
void didChangeDependencies() {
super.didChangeDependencies();
if(_errorsSubscription == null) {
_errorsSubscription = SyncErrorProvider.of(context).errors.listen((error) {
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(error.toString())));
});
}
}
@override
void dispose() {
_errorsSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: ...,
);
}
}
This scaffold would only be used for snackbars, nothing else. Advantage is that the errors are always guaranteed to be visible, disadvantage that they will overlap FABs and bottom bars.
class MyApp extends StatefulWidget {
final Stream