Что такое дерево виджетов во Flutter
Что проверяют
Знаете ли вы, что за словами «дерево виджетов» стоят три дерева, и понимаете ли, почему build() можно вызывать хоть каждый кадр. Следом спрашивают про ключи, про то, что именно пересобирает setState, и про const-конструкторы.
Как отвечать
- Widget: неизменяемое описание, конфигурация. Создаётся заново при каждом
build()и стоит дёшево, это обычный лёгкий объект; - Element: экземпляр виджета в конкретном месте дерева. Живёт между перестроениями, хранит связи с родителем и детьми, а у
StatefulWidgetдержит объектState.BuildContext, который приходит вbuild(), и есть этот элемент; - RenderObject: отвечает за layout, отрисовку и hit testing. Есть не у каждого виджета:
PaddingиRowего создают, аStatelessWidgetтолько собирает другие виджеты.
Когда вызывается setState, элемент помечается грязным, и на следующем кадре пересобирается его поддерево, а не весь экран. Для каждого нового виджета Flutter проверяет Widget.canUpdate: если совпали runtimeType и key, существующий элемент получает новую конфигурацию и сохраняет State, иначе элемент со всем поддеревом создаётся заново. Фронтендеру полезно сравнить это с согласованием в React, где решают тот же тип компонента и key.
Отсюда практика: выносить часто меняющиеся части в отдельные небольшие виджеты, помечать неизменяемые поддеревья const (идентичный экземпляр Flutter не пересобирает), получать общие данные через InheritedWidget, Provider или Riverpod, чтобы перестраивались только подписчики.
Где спотыкаются
Считают, что виджет это то, что нарисовано на экране, и что пересоздавать виджеты дорого. Дорого перестраивать элементы и рендер-объекты, а виджеты как раз одноразовые.
Не ставят ключи в списках, где элементы переставляются или удаляются. Элементы сопоставляются по позиции, и State одной строки, например введённый текст или отмеченный чекбокс, переезжает к соседней.
Вызывают setState в корне большого экрана ради одного счётчика и держат тяжёлые вычисления прямо в build(). Метод вызывается часто, и каждая лишняя работа в нём превращается в пропущенные кадры.