Метод побудови розроблений таким чином, що він повинен бути чистим / без побічних ефектів . Це пов’язано з тим, що багато зовнішніх факторів можуть викликати нову збірку віджетів, наприклад:
- Маршрут поп / push
- Зміна розміру екрана, як правило, через зовнішній вигляд клавіатури або зміну орієнтації
- Батьківський віджет відтворив свою дитину
- InheritedWidget віджет залежить від (
Class.of(context)
шаблону) зміни
Це означає, що build
метод не повинен викликати http-дзвінок або змінювати будь-який стан .
Як це пов’язано з питанням?
Проблема, з якою ви стикаєтесь, полягає в тому, що ваш метод збірки має побічні ефекти / не є чистим, що робить сторонні дзвінки побудови складними.
Замість того, щоб запобігати побудові виклику, ви повинні зробити свій метод збірки чистим, щоб його можна було викликати в будь-який час без впливу.
У випадку з вашим прикладом ви перетворите свій віджет у StatefulWidget
витяг, який виклик HTTP у initState
ваш State
:
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
Future<int> future;
@override
void initState() {
future = Future.value(42);
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: future,
builder: (context, snapshot) {
// create some layout here
},
);
}
}
Я це вже знаю. Я прийшов сюди, бо дуже хочу оптимізувати перебудови
Можна також зробити віджет, здатний відбудовуватися, не примушуючи своїх дітей також будувати.
Коли примірник віджета залишається таким же; Флетер цілеспрямовано не відновлює дітей. Це означає, що ви можете кешувати частини дерева віджетів, щоб уникнути зайвих перебудов.
Найпростіший спосіб - використовувати const
конструктори дротиків :
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(),
child: Text("Hello World"),
);
}
Завдяки цьому const
ключовому слову, примірник DecoratedBox
залишиться колишнім, навіть якщо збірка називалася сотні разів.
Але ви можете досягти того ж результату вручну:
@override
Widget build(BuildContext context) {
final subtree = MyWidget(
child: Text("Hello World")
);
return StreamBuilder<String>(
stream: stream,
initialData: "Foo",
builder: (context, snapshot) {
return Column(
children: <Widget>[
Text(snapshot.data),
subtree,
],
);
},
);
}
У цьому прикладі, коли StreamBuilder буде повідомлено про нові значення, subtree
він не відбудується, навіть якщо StreamBuilder / Column. Це трапляється тому, що, завдяки закриттю, примірник MyWidget
не змінився.
Цей візерунок багато використовується в анімації. Типовими є використання AnimatedBuilder
та всі переходи, такі як AlignTransition
.
Ви також можете зберігати subtree
в полі свого класу, хоча і не рекомендується, оскільки воно порушує функцію гарячого перезавантаження.