Я относительно новичок во Флаттере и в настоящее время борюсь с FutureBuilders. Я прочитал ответ Реми в этой ветке , в которой в основном изложена философия Флаттера о том, что сборки виджетов должны быть идемпотентными. Я понимаю принцип в теории, но как это работает на практике?
Рассмотрим следующий фрагмент:
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Consumer<DataPresenter>(
builder: (context, presenter, _) {
return DefaultFutureBuilder<List<Data>>(
future: presenter.data(),
builder: (context, data) {
// bla bla
}
);
}
),
// More widgets
],
),
),
);
}
Где это мой DefaultFutureBuilder
:
class DefaultFutureBuilder<T> extends StatelessWidget {
final Future<T> future;
final Widget Function(BuildContext, T data) builder;
final Widget Function(BuildContext) errorBuilder;
DefaultFutureBuilder({
@required this.future,
@required this.builder,
this.errorBuilder,
});
@override
Widget build(BuildContext context) {
var errBuilder = errorBuilder ?? _buildDefaultErrorScreen;
return FutureBuilder<T>(
future: future,
builder: (context, snapshot) {
var indicator = Center(child: CircularProgressIndicator());
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData)
return builder(context, snapshot.data);
else if (snapshot.hasError)
return errBuilder(context);
}
return indicator;
},
);
}
Widget _buildDefaultErrorScreen(BuildContext context) {
// default
}
}
Теперь я знаю что вызов presenter.data()
(извлекает данные asyn c) не кошерный. Но я делаю хочу повторно извлечь данные, когда докладчик уведомляет потребителя, и в то же время я не хочу извлекать их, когда Flutter перестраивает мое дерево виджетов из-за структурных махинаций.
Моя первоначальная идея состояла в том, чтобы построить презентатор так, чтобы он получал данные только тогда, когда у него нет данных в данный момент. Затем я мог бы установить для данных значение null из других методов и уведомить слушателей о необходимости перестроить поддеревья виджетов, на которые влияют.
Примерно так:
class DataPresenter extends ChangeNotifier {
// fields, services, bla bla
List<Data> _data;
Future<List<Data>> data() async {
if (_data == null) {
var response = await _service.fetchMyStuff(params: params);
_data = response.data;
}
return _data;
}
}
Проблема с этим решением состоит в том, что любые перестройки, которые происходят, пока я получение данных в первый раз вызовет другой запрос.
Буду признателен, если кто-то сможет указать, какую часть фреймворка / архитектуры я не получил.