我有一个使用Flutter- Redux的应用程序。在某些用户操作上,将分派各种还原操作,并且这些操作在中间件中异步运行。我现在的问题是:万一出问题了,我该如何从中间件中显示SnackBar。我不能使用回调,因为不能保证派发动作的Widget仍然可用。错误将是:
此时,小部件的元素树的状态不再稳定。要在其dispose()方法中安全地引用窗口小部件的祖先,请通过在窗口小部件的didChangeDependencies()方法中调用InheritFromWidgetOfExactType()来保存对祖先的引用。
例:
现在…例如,当rest调用返回错误时,由于“很长一段时间”而关闭了该对话框,其上下文无效,并且我无法显示SnackBar。
进一步:
SnackBar必须始终绑定到脚手架。因此,我已经尝试制作一个空的root- Scaffold并通过GlobalKey引用它。这就带来了一个问题,即当另一个窗口小部件位于根窗口小部件上方且用户无法读取时,SnackBar被隐藏了。
有什么建议如何解决这个问题?
最好的问候,弗洛里安
对于“一次性错误”,redux有点笨拙。一般来说,有两种处理方法:
我不确定中间件的外观如何,但是在网络请求失败后,您会将错误对象推送到rxdart Subject或中StreamController。现在您有一个Stream错误。
Subject
StreamController
Stream
作为您的直接子级StoreProvider,创建自己InheritedWidget的错误流,名为SyncErrorProvider:
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).errorsfrom 从任何路径访问错误流didChangeDependencies。
MaterialApp
SyncErrorProvider.of(context).errors
didChangeDependencies
在小吃店中显示错误有点困难,因为小吃店的位置取决于页面布局(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, ); }, ); } }