В чем разница StatelessWidget и StatefulWidget во Flutter и когда использовать каждый
Что проверяют
Понимаете ли вы, где во Flutter живёт состояние и что происходит при перестроении. Следом обычно спрашивают про жизненный цикл State и про то, зачем виджетам нужны ключи.
Как отвечать
Оба вида виджетов неизменяемы: виджет это лёгкая конфигурация, которую родитель создаёт заново при каждом своём build. Разница в том, где хранится изменяемая часть:
- StatelessWidget: результат
buildзависит только от параметров конструктора и от унаследованных данных черезcontext, напримерTheme.of(context)илиMediaQuery.of(context). Он перестраивается, когда перестроился родитель или изменились эти зависимости; - StatefulWidget: виджет тоже неизменяем, но через
createState()создаёт объектState, который привязан к элементу и переживает перестроения.setState()помечает элемент грязным, и в следующем кадре вызываетсяbuild.
Жизненный цикл State: initState один раз при вставке, didChangeDependencies при смене унаследованных данных, didUpdateWidget при приходе новой конфигурации от родителя, dispose для освобождения AnimationController, TextEditingController, подписок на стримы. После асинхронной операции проверяйте mounted, прежде чем вызывать setState.
Когда что брать. Stateful нужен для локального, короткоживущего состояния интерфейса: контроллер поля ввода, анимация, выбранная вкладка. Состояние приложения выносят в Provider, Riverpod или Bloc, и тогда экран часто остаётся Stateless. Если вы пришли из React, аналогия простая: State похож на состояние компонента, а setState запускает повторный рендер.
Где спотыкаются
Говорят, что StatelessWidget никогда не перестраивается и поэтому быстрее. Производительность определяет объём перестраиваемого поддерева: помогают const-конструкторы и дробление на мелкие виджеты, а не выбор базового класса.
Хранят изменяемые данные в полях самого StatefulWidget. При следующем build родителя виджет пересоздаётся, и значение теряется. Место состояния в State.
Не ставят ключи в списках из Stateful-элементов. При удалении или перестановке состояние остаётся привязанным к позиции, и галочка «переезжает» на соседнюю строку. Помогает ValueKey(item.id).