我有一个使用Flutter-Redux的应用程序。 在某些用户操作上,将分派各种还原操作,并且这些操作在中间件中异步运行。 我现在的问题是:万一出问题了,我如何从中间件显示SnackBar。 我不能使用回调,因为不能保证派发动作的Widget仍然可用。错误可能是:
此时,小部件的元素树的状态不再 稳定。为了安全地在其dispose()中引用小部件的祖先 方法,通过调用保存对祖先的引用 小部件的didChangeDependencies()中的InheritFromWidgetOfExactType() 方法。
示例:
现在...例如其余调用返回错误,对话框已关闭很长时间了,其上下文无效,并且我无法显示SnackBar。
进一步:
SnackBar必须始终绑定到脚手架。因此,我已经尝试制作一个空的root-Scaffold并通过GlobalKey引用它。这就带来了一个问题,即当另一个窗口小部件位于根窗口小部件上方且用户无法读取时,SnackBar被隐藏。
任何建议如何解决此问题?
最好的问候, 弗洛里安
答案 0 :(得分:5)
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,
);
},
);
}
}