我有一个使用Flutter-Redux的应用程序。在某些用户操作中,将调度各种redux-actions,并在中间件中异步运行。我现在的问题是:如果出现问题,如何从中间件显示SnackBar。我无法使用回调,因为无法保证调度操作的Widget仍然可用。错误将是:
此时,窗口小部件元素树的状态不再稳定。要在dispose()方法中安全地引用窗口小部件的祖先,请通过在窗口小部件的didChangeDependencies()方法中调用inheritFromWidgetOfExactType()来保存对祖先的引用。
例:
现在......当...其余的调用返回错误,对话框因“长”时间关闭,其上下文无效,我无法显示SnackBar。
进一步:
SnackBar必须始终绑定到脚手架。所以我已经尝试制作一个空的根-Faffold并通过GlobalKey引用它。这带来了当另一个小部件位于根小部件上并且用户无法读取时SnackBar被隐藏的问题。
有什么建议如何解决这个问题?
最好的问候,弗洛里安
对于“一次性错误”,redux有点笨拙。一般来说,有两种方法可以处理它:
我不确定你的中间件究竟是什么样子,但是在网络请求失败后,你会将错误对象推送到rxdart Subject
或StreamController
。现在你有一个Stream
的错误。
作为你的StoreProvider
的直接孩子,创建你自己的InheritedWidget
,其中包含错误流,名为SyncErrorProvider
:
class SyncErrorProvider extends InheritedWidget {
const SyncErrorProvider({Key key, this.errors, @required Widget child})
: assert(child != null),
super(key: key, child: child);
final Stream<Object> errors;
static SyncErrorProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(SyncErrorProvider) as SyncErrorProvider;
}
@override
bool updateShouldNotify(SyncErrorProvider old) => errors != old.errors;
}
继承的小部件应该包装你的MaterialApp
。现在,您可以使用SyncErrorProvider.of(context).errors
中的didUpdateDependencies
以简单的方式从任何路径访问错误流。
在快餐栏中显示错误是一个挑战,因为小吃店的位置取决于页面布局(FAB,底部导航...),有时候出现的小吃栏会移动其他UI元素。
处理零食栏创建的最佳方式取决于您的应用程序。我也不确定这些错误会发生多久,所以也许不要花太多时间。
两种不同的方法有优点和缺点:
在每个有脚手架的屏幕上,聆听错误流并在当地脚手架中展示小吃店。确保在处理小部件时取消订阅。
这种方法的优点是小吃店是页面UI的一部分,并将移动脚手架的其他元素。
缺点是如果有没有脚手架的对话框或屏幕,则错误将不可见。
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
StreamSubscription _errorsSubscription;
final _scaffoldKey = GlobalKey<ScaffoldState>();
@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: ...,
);
}
}
这个脚手架只能用于零食吧,没有别的。优点是始终保证错误是可见的,缺点是它们将与FAB和底部条重叠。
class MyApp extends StatefulWidget {
final Stream<Object> syncErrors; // coming from your store/middleware
MyApp({Key key, this.syncErrors}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
StreamSubscription _errorsSubscription;
final _errorScaffoldKey = GlobalKey<ScaffoldState>();
@override
void initState() {
// TODO: implement initState
super.initState();
_errorsSubscription = widget.syncErrors.listen((error) {
_errorScaffoldKey.currentState.showSnackBar(SnackBar(content: Text(error.toString())));
});
}
@override
void dispose() {
_errorsSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) {
Scaffold(
key: _errorScaffoldKey,
body: child,
);
},
);
}
}