В чем разница между StatefulWidget, StatelessWidget и InheritedWidget?

«В чем разница между StatefulWidget, StatelessWidget и InheritedWidget?» — вопрос из категории Flutter виджеты, который задают на 36% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Это три фундаментальных типа виджетов во Flutter с разным предназначением:

  1. StatelessWidget

    • Неизменяемый (immutable). Все его поля должны быть final.
    • Не хранит собственное изменяемое состояние. Он описывает часть UI, которая зависит только от своих входных параметров (props) и контекста.
    • Создается заново при каждом изменении родительского виджета.

      class MyTitle extends StatelessWidget {
      final String text; // Параметр — final поле
      const MyTitle(this.text, {super.key});
      
      @override
      Widget build(BuildContext context) {
      return Text(text, style: Theme.of(context).textTheme.headlineMedium);
      }
      }
  2. StatefulWidget

    • Состоит из двух классов: сам неизменяемый виджет (StatefulWidget) и изменяемый объект состояния (State).
    • Хранит изменяемое состояние (данные, которые могут меняться в течение жизни виджета).
    • Перестраивает UI при вызове setState() в его объекте State.

      
      class Counter extends StatefulWidget {
      const Counter({super.key});
      
      @override
      State<Counter> createState() => _CounterState();
      }

    class _CounterState extends State { int _count = 0; // Изменяемое состояние

    void _increment() { setState(() { // Триггер перерисовки _count++; }); }

    @override Widget build(BuildContext context) { return ElevatedButton( onPressed: _increment, child: Text('Нажато $_count раз'), ); } }

  3. InheritedWidget

    • Специальный виджет для эффективного распространения данных вниз по дереву.
    • Позволяет любому потомку в поддереве получить доступ к данным без их явной передачи через конструкторы каждого промежуточного виджета (решает "проблему проваливания пропсов").
    • Ключевой механизм для таких сущностей, как Theme, MediaQuery, а также для state-менеджмента в пакетах вроде Provider.
      // Потомок получает данные через статический метод .of(context)
      final themeData = Theme.of(context);
      final screenSize = MediaQuery.of(context).size;

Итог: Stateless и Stateful — строительные блоки UI. InheritedWidget — это инфраструктурный виджет для передачи данных и управления зависимостями.