Как устроен жизненный цикл виджетов во Flutter
Что проверяют
Понимаете ли вы, что виджет во Flutter это неизменяемое описание, а между кадрами живёт State, и знаете ли, в каком методе что делать. Следом почти всегда спрашивают, зачем нужен didChangeDependencies и что будет от setState после ухода с экрана.
Как отвечать
Начните с трёх деревьев: виджеты (конфигурация, пересоздаются при каждой перестройке), элементы (держат место в дереве и State) и RenderObject для раскладки и отрисовки. Поэтому пересоздать виджет дёшево, а состояние при этом сохраняется.
У StatelessWidget цикла почти нет: только build, который вызывается при перестройке родителя или при изменении InheritedWidget, от которого он зависит. У StatefulWidget порядок такой:
createState: фреймворк создаётStateи связывает его с элементом,mountedстановитсяtrue;initState: один раз. Здесь создают контроллеры и подписки, запускают загрузку.Theme.of(context)и прочие зависимости отInheritedWidgetздесь не читают;didChangeDependencies: сразу послеinitStateи потом при каждой смене унаследованной зависимости. Место дляMediaQuery,Theme, провайдеров;build: вызывается часто, поэтому только построение дерева, без запросов и тяжёлых вычислений;didUpdateWidget: родитель передал новый виджет того же типа с тем же ключом. СравниваетеoldWidgetсwidgetи при необходимости переподписываетесь;setState: помечает элемент грязным,buildслучится в следующем кадре;deactivateиdispose: элемент убран из дерева, вdisposeосвобождают ресурсы.
Фронтендеру полезна параллель с React: initState похож на эффект с пустым списком зависимостей, dispose на его функцию очистки.
Где спотыкаются
Говорят, что StatelessWidget строится один раз. Он перестраивается так же часто, как родитель, просто без своего состояния.
Вызывают setState после await, когда экран уже закрыт, и получают ошибку. Перед вызовом проверяют mounted.
Забывают dispose у AnimationController, TextEditingController и подписок на Stream. Итог: утечки и колбэки в мёртвый State.