По разным причинам иногда build
метод моих виджетов вызывается повторно.
Я знаю, что это происходит из-за обновления родителей. Но это вызывает нежелательные эффекты. Типичная ситуация, когда это вызывает проблемы, при использовании FutureBuilder
этого способа:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: httpCall(),
builder: (context, snapshot) {
// create some layout here
},
);
}
В этом примере, если бы метод сборки был вызван снова, он инициировал бы другой HTTP-запрос. Что нежелательно.
Учитывая это, как бороться с нежелательной сборкой? Есть ли способ предотвратить вызов сборки?
flutter
flutter-widget
Реми Русселе
источник
источник
Ответы:
Метод сборки разработан таким образом, что он должен быть чистым / без побочных эффектов . Это связано с тем, что многие внешние факторы могут вызвать создание нового виджета, например:
Class.of(context)
шаблон)Это означает, что
build
метод не должен запускать http-вызов или изменять какое-либо состояние .Как это связано с вопросом?
Проблема, с которой вы столкнулись, заключается в том, что ваш метод сборки имеет побочные эффекты / не является чистым, что затрудняет посторонний вызов сборки.
Вместо того, чтобы предотвращать вызов сборки, вы должны сделать свой метод сборки чистым, чтобы его можно было вызывать в любое время без каких-либо последствий.
В случае вашего примера вы должны преобразовать свой виджет в, а
StatefulWidget
затем извлечь этот HTTP-вызов вinitState
свойState
:Также возможно сделать виджет способным к перестройке, не заставляя его дочерние элементы тоже строить.
Когда экземпляр виджета остается прежним; Flutter намеренно не восстанавливает детей. Это означает, что вы можете кэшировать части своего дерева виджетов, чтобы предотвратить ненужные перестроения.
Самый простой способ - использовать
const
конструкторы дротиков :Благодаря этому
const
ключевому слову экземплярDecoratedBox
останется прежним, даже если сборка вызывалась сотни раз.Но вы можете добиться того же результата вручную:
В этом примере, когда StreamBuilder получает уведомление о новых значениях,
subtree
он не будет перестраиваться, даже если StreamBuilder / Column это сделает. Это происходит потому, что благодаря закрытию экземплярMyWidget
не изменился.Этот паттерн часто используется в анимации. Типичное использование -
AnimatedBuilder
и все переходы, такие какAlignTransition
.Вы также можете сохранить
subtree
в поле своего класса, хотя это менее рекомендуется, поскольку это нарушает функцию горячей перезагрузки.источник
subtree
в поле класса прерывает горячую перезагрузку?StreamBuilder
заключается в том, что при появлении клавиатуры экран меняется, поэтому маршруты необходимо перестраивать. ИтакStreamBuilder
, перестраивается, создается новыйStreamBuilder
и подписывается наstream
. Когда aStreamBuilder
подписывается на astream
,snapshot.connectionState
становится,ConnectionState.waiting
что заставляет мой код возвращать aCircularProgressIndicator
, а затемsnapshot.connectionState
изменяется, когда есть данные, и мой код возвращает другой виджет, который заставляет экран мерцать разными вещами.StatefulWidget
, подписатьсяstream
наinitState()
и установитьcurrentWidget
с,setState()
поскольку онstream
отправляет новые данные, передаваяcurrentWidget
ихbuild()
методу. Есть ли лучшее решение?FutureBuilder
.Вы можете предотвратить нежелательный вызов сборки, используя этот способ
1) Создайте дочерний класс Statefull для отдельной небольшой части пользовательского интерфейса
2) Используйте библиотеку Provider , чтобы с ее помощью можно было остановить вызов нежелательного метода сборки.
В приведенных ниже ситуациях вызов метода сборки
источник
Flutter также имеет
ValueListenableBuilder<T> class
. Это позволяет вам перестроить только некоторые из виджетов, необходимых для вашей цели, и пропустить дорогие виджеты.вы можете увидеть документы здесь ValueListenableBuilder flutter docs
или просто пример кода ниже:
источник