Ответ
В Flutter есть два фундаментальных типа виджетов с разными жизненными циклами: StatelessWidget и StatefulWidget.
StatelessWidget
Иммутабельный виджет, который описывает часть UI, зависящую только от своих конфигурационных параметров (final поля, переданные в конструктор). Его жизненный цикл прост:
- Конструктор: Принимает
keyи другие параметры. - build(BuildContext context): Вызывается фреймворком, когда виджет должен отрисоваться.
- Уничтожение: Экземпляр может быть собран сборщиком мусора. Если внутри
buildсоздаются подписки или контроллеры (что не рекомендуется), их нужно управлять через родительскийStatefulWidget.
class MyStatelessButton extends StatelessWidget {
const MyStatelessButton({
super.key,
required this.label,
required this.onPressed,
});
final String label;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(label),
);
}
}
StatefulWidget
Виджет, который может менять свое состояние во времени. Его жизненный цикл сложнее и сосредоточен в отдельном объекте State.
Последовательность методов State объекта:
- createState() (метод
StatefulWidget) - mounted = true
- initState()
- didChangeDependencies()
- build() (многократно)
- didUpdateWidget() (при обновлении конфигурации)
- setState() (триггер из кода)
- deactivate()
- dispose()
- mounted = false
Ключевое отличие: StatefulWidget сам по себе — это всего лишь конфигурация (и он пересоздается при каждом обновлении родителя). Долгоживущая логика и состояние хранятся в ассоциированном объекте State, который фреймворк может переиспользовать при обновлении родительского виджета с тем же runtimeType и key.
Ответ 18+ 🔞
Давай разберём эту тему, чтобы в голове всё встало на свои места, а не болталось как хуй в проруби.
Вот смотри, в Flutter'е есть два главных типа виджетов, и вся разница между ними — как между табуреткой и трансформером. Первый — StatelessWidget. Это как та самая простая табуретка: собрали один раз из трёх досок и гвоздя, и всё. Больше она не меняется. Всё, что ей нужно для жизни — это параметры, которые ты в неё вбил при создании. final поля, конструктор — и поехали. Его жизненный цикл проще пареной репы: конструктор, метод build, и на этом всё, приехали. Собрали, отрисовали, забыли. Если ты внутри build начнёшь создавать какие-то подписки или контроллеры — это пиздец, чувак, так делать нельзя. Это всё равно что приколачивать к табуретке мотор от мопеда — вроде и прикрутил, а толку? Управлять этим нечем. Для такого дерьма нужен уже второй тип.
class MyStatelessButton extends StatelessWidget {
const MyStatelessButton({
super.key,
required this.label,
required this.onPressed,
});
final String label;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(label),
);
}
}
А вот второй — StatefulWidget. Это уже наш трансформер. Он может меняться, шевелиться, обновляться. И вся его магия, вся соль — спрятана в отдельном объекте под названием State. Сам по себе StatefulWidget — это просто конфиг, бумажная инструкция. Он пересоздаётся каждый раз, когда родительский виджет обновляется. А вот объект State — это уже живая душа, которая может пережить своего создателя и хранить в себе все данные.
Жизненный цикл у этого State — целая эпопея, ёпта. Запоминай:
- Вызывается
createState()(это ещё метод виджета). - Флаг
mountedстановитсяtrue. Это важно, иначе потом будешь охуевать от ошибок. initState()— святое место. Тут инициализируешь всё, что должно жить долго: контроллеры, подписки, загружаешь данные. Вызывается один раз за жизньState.didChangeDependencies()— может вызваться несколько раз. Срабатывает, когда зависящие от контекста штуки (вродеInheritedWidget) меняются.build()— а вот это вызывается дохуя раз. Здесь ты описываешь, как должен выглядеть интерфейс прямо сейчас, на основе текущего состояния.didUpdateWidget()— если родитель обновил наш виджет с новыми параметрами, ноStateрешили оставить старый, то вызывается этот метод. Тут можно сравнить старый и новый виджет и что-то подкрутить.setState()— это не метод жизненного цикла, а твой главный инструмент. Ты вызываешь его из кода, когда нужно сказать фреймворку: «Эй, состояние поменялось, перерисуй виджет, ёпта!». Внутри него меняешь данные и триггеришь новыйbuild.deactivate()— виджет временно убирают из дерева, ноStateещё может вернуться. Редко используется.dispose()— финал, капут. Здесь ОБЯЗАТЕЛЬНО нужно почистить за собой: закрыть все контроллеры, отписаться от стримов, освободить ресурсы. После этогоStateумрёт.- Флаг
mountedстановитсяfalse. Теперь если попробуешь вызватьsetState()— получишь ошибку, что виджет не смонтирован. Сам от себя охуеешь, но виноват будешь только ты.
Вот и вся разница, бля. Stateless — статичный кусок интерфейса. Stateful — динамичная хуйня с мозгом (State), которая умеет реагировать, меняться и помнить. Главное — не перепутай, где что использовать, а то получится пиздопроебибна архитектура.