redux немного неуклюже, когда дело доходит до «одноразовых ошибок». В общем, есть 2 способа справиться с этим:
- Вы можете сохранить ошибки в хранилище и отобразить наложение ошибок, пока в магазине существует ошибка. Удалите ошибку из магазина, чтобы закрыть оверлей.
- Рассматривать отображение ошибки как «одноразовый» побочный эффект (как при воспроизведении звука). Я думаю, что это лучшее решение, особенно если вы хотите использовать закусочные.
Я не уверен, как именно выглядит ваше промежуточное ПО, но после сбоя сетевого запроса вы поместите объект ошибки в 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, нижняя навигация ...), и иногда появляющийся снэк-бар перемещает другие элементы пользовательского интерфейса.
Лучший способ создания закусочной зависит от вашего приложения. Я также не уверен, как часто эти ошибки будут появляться, поэтому, возможно, не тратьте на это слишком много времени.
Два разных подхода с преимуществами и недостатками:
Отображать ошибки в каркасах страниц
На каждом экране, на котором есть эшафот, слушайте поток ошибок и отображайте закусочные в локальном эшафоте. Обязательно отмените подписку при удалении виджетов.
Преимущество этого подхода заключается в том, что закусочные являются частью пользовательского интерфейса страницы и будут перемещать другие элементы каркаса.
Недостатком является то, что при наличии диалогов или экранов без каркаса ошибка не будет видна.
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,
);
},
);
}
}