Closed jans-y closed 5 years ago
@jans-y (Caution this may be bad advice 🤷♂)
I am personally trying to remove any reference to context
whether it be directly (by passing context to an action), or indirectly (by using a global key such as navigatorKey and getting the context that way) to Actions.
Instead, I am leveraging Event
s to signal that something like that needs to be done, and then consuming the events in a didUpdateWidget
method.
For example:
@override
void didUpdateWidget(MyWidget oldWidget) {
super.didUpdateWidget(oldWidget);
consumeEvents(context);
}
void consumeEvents(BuildContext context) {
if (widget.showDialogEvt.consume()) { // code to showDialog here }
}
So you can have a setShowDialogAction
that sets the showDialogEvt
in its reduce
method ... and then you can call setShowDialogAction
in the before
method of another action
@gadfly361 is right. Usually Events are the way to go when you need to display dialogs. Why? Actions belong to the "business layer", and they should not know about Flutter widgets, let alone contexts, which are in the "client/UI layer". So you should use an Event to signal to some widget that it needs to open a dialog.
Just to complement Matthew's answer:
abstract class BarrierAction extends ReduxAction<AppState> {
Future before() async {
dispatch(SetLoadingAction(true));
if (!hasConnection) return state(hasNoConnectionEvt: Event());
else return null;
}
}
One of your widgets should be listening to store.state.hasNoConnectionEvt
, and will consume the Event and show a dialog, as Matthew explained.
However, if all you want is a dialog with some text that displays an error message, then there is no need to do any of that. You can just throw an UserException:
abstract class BarrierAction extends ReduxAction<AppState> {
Future before() async {
dispatch(SetLoadingAction(true));
if (!hasConnection) throw UserException("Please check your internet connection.");
else return null;
}
}
This UserException will be caught by AsyncRedux, which will display a dialog with the message. For more details on how to setup AsyncRedux to display these dialogs, see this: https://pub.dev/packages/async_redux#user-exceptions
Thank you for your guidance.
This library is evolving so rapidly that I have must missed the UserException.
It works ok, but I will probably end up building my own "UserException" class which will show Cupertino dialog on iOS and possibly a SnackBar.
@jans-y That surely is a good idea of improving the UserExceptionDialog class. Please share your implementation here if you can. Thanks.
Hi,
I forked it locally and did this:
BuildContext context,
UserException userException,
) {
if (Platform.isIOS) {
showCupertinoDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text(userException.dialogTitle()),
content: Text(userException.dialogContent()),
actions: [
CupertinoDialogAction(
child: Text("OK"),
onPressed: () => Navigator.of(context).pop(),
)
],
),
);
} else {
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text(userException.dialogTitle()),
content: Text(userException.dialogContent()),
actions: [
FlatButton(
child: Text("OK"),
onPressed: () => Navigator.of(context).pop(),
)
],
),
);
}
}```
@jans-y Added this to version 2.3.3.
Hi,
Thank you for adding the code I proposed before. I have started to experiment with Flutter for web and found out that it has to be update to not break web compilation:
➕add import
import 'package:flutter/foundation.dart';
Change condition 📱
if (Platform.isIOS) {
⬇️
if (!kIsWeb && (Platform.isMacOS || Platform.isIOS)) {
I would create PR but I never did it on GitHub on someone's others project.
Thank you.
Done: version 2.4.3.
Hi,
I really enjoy using your library. It makes it so much easier to use the Redux with Flutter. Thank you.
I would like to ask how can I get a correct context to be able to display Dialog or SnackBar from the before method inside an abstract class.
I was hoping something like navigatorKey.currentState.context would work but I wasn't successful.
I have also tried passing current context to the Action itself ->
store.dispatch(SomeAction(context))
but I don't know how to pass it into the before method without overriding it, which adds (maybe) unnecessary complexity.Thank you for your advice.