Виджеты и композиция
Всё на экране — виджет, и виджеты не объекты, которые изменяют, а дешёвые описания: фреймворк пересоздаёт их постоянно. Код на Flutter становится читаемым тогда, когда это перестаёт удивлять, а интерфейс собирается из мелких виджетов вместо наращивания больших.
Почему это важно. Почти все проблемы вида «Flutter тормозит» и «состояние куда-то пропало» растут из модели, в которой виджет — долгоживущий объект. Это не так, и поведение фреймворка становится осмысленным только после того, как это укладывается в голове.
Что нужно понимать
- Зачем нужен
build: описывать, а не делать - Что переживает перестроение, а что нет
- Почему фреймворк считает два виджета одним и тем же — или разными
- Когда кусок интерфейса пора выносить в отдельный виджет
- Что такое const и на чём он экономит
Основные темы
Деревья
- Widget, element и render object — три дерева и задача каждого
- Перестроение и почему оно дёшево по замыслу
- Ключи: когда важна идентичность и во что обходятся
ValueKeyиGlobalKey BuildContextкак позиция в дереве, а не мешок с данными
Stateless и stateful
- Где живёт состояние и как поднимать его выше
initState,didUpdateWidget,dispose— и что относится к каждому из них- Почему в
buildне должно быть побочных эффектов StatefulWidgetпротив отдельного решения для управления состоянием
Композиция
- Мелкие виджеты вместо длинных методов
build - Метод, возвращающий виджет, против настоящего класса-виджета — и почему разница существенна
- Билдеры, слоты и передача children вместо конфигурации
InheritedWidgetи чтение данных сверху
Перестроения
- Что запускает перестроение и как далеко оно расходится
const-конструкторы и перестроения, которых они позволяют избежать- Перестроение поддерева вместо целого экрана
- Как распознать дорогой
build
Уровни
| Уровень | Как это выглядит |
|---|---|
| Junior | Собирает экраны из готовых виджетов. Корректно пользуется setState. |
| Middle | Разбивает интерфейс на мелкие виджеты, понимает дерево элементов достаточно, чтобы объяснить ключи, и контролирует область перестроения. |
| Senior | Проектирует переиспользуемые API виджетов, осознанно применяет ключи и жизненный цикл, диагностирует проблемы перестроения и компоновки по дереву. |
Практика
Для начала
-
Разберите метод
buildна части Возьмитеbuildдлиннее сотни строк и разложите его на именованные виджеты. -
Расставьте const везде, где можно Включите линт, устраните предупреждения и посмотрите на число перестроений.
-
Проследите за перестроением Счётчики перестроений в инспекторе покажут, как далеко достаёт один
setState.
Глубже
-
Там, где нужен ключ Соберите список stateful-элементов с изменением порядка и найдите баг, который лечится только ключом.
-
Спроектируйте API виджета Напишите переиспользуемый виджет, которым будут пользоваться другие, и сделайте неправильное применение невозможным.
-
Сузьте слишком широкое перестроение Найдите
setState, который перестраивает пол-экрана, и ограничьте его.
Проверьте себя
- Что именно происходит между
setStateи изменением пикселей на экране? - Почему состояние иногда прилипает не к тому элементу списка?
- Когда вспомогательный метод, возвращающий виджет, — неверный выбор?
- Что в вашем самом длинном
buildтам быть не должно? - Как узнать, что именно перестраивается и как часто?
- Когда
GlobalKeyобходится дороже, чем даёт?
Материалы
- Introduction to widgets — официальная точка входа: композиция и разделение на stateful и stateless.
- Flutter architectural overview — три дерева и путь от фреймворка до GPU. Самая полезная страница из всех: после неё остальное перестаёт казаться произвольным.
- Inside Flutter — почему перестроения дёшевы, написано теми, кто их такими сделал. Разбирает алгоритмы, стоящие за наблюдаемым поведением.
- When to use keys — объяснение от команды Flutter; именно после него у большинства ключи встают на место.
- Flutter Widget of the Week — по одному виджету за минуту, от команды. Самый дешёвый способ узнать, что уже есть, прежде чем писать своё.