← Назад к вопросам

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

1.0 Junior🔥 231 комментариев
#Flutter виджеты

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между StatefulWidget, StatelessWidget и InheritedWidget

Это фундаментальные концепции в Flutter для управления состоянием. Каждый тип виджета имеет свою роль и применение.

StatelessWidget

StatelessWidget — это виджет, который не имеет изменяемого состояния. Его внешний вид полностью определяется параметрами, которые передаются в конструктор. Он не может изменяться самостоятельно.

class GreetingWidget extends StatelessWidget {
  final String name;

  const GreetingWidget({required this.name});

  @override
  Widget build(BuildContext context) {
    return Text('Привет, $name!');
  }
}

Характеристики:

  • Неизменяемый (immutable)
  • Не имеет State
  • Использует только конструктор параметры
  • Быстрый и легкий
  • Идеален для статичного контента

StatefulWidget

StatefulWidget — это виджет, который может иметь внутреннее состояние (State), которое может меняться во время жизни приложения. Это позволяет виджету перерисовываться при изменении состояния.

class CounterWidget extends StatefulWidget {
  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Счётчик: $_counter'),
        ElevatedButton(
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
          child: Text('Увеличить'),
        ),
      ],
    );
  }
}

Характеристики:

  • Имеет внутреннее состояние
  • Вызывает setState() для обновления UI
  • Может изменяться во времени
  • Более ресурсоёмкий, чем StatelessWidget
  • Используется для интерактивных элементов

InheritedWidget

InheritedWidget — специальный виджет для передачи данных вниз по дереву виджетов. Вместо того чтобы передавать параметры через каждый уровень вложенности, можно использовать InheritedWidget для доступа к данным из любого потомка через BuildContext.

class ThemeData extends InheritedWidget {
  final Color primaryColor;
  final TextStyle titleStyle;

  const ThemeData({
    required this.primaryColor,
    required this.titleStyle,
    required Widget child,
  }) : super(child: child);

  static ThemeData of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<ThemeData>()!;
  }

  @override
  bool updateShouldNotify(ThemeData oldWidget) {
    return primaryColor != oldWidget.primaryColor ||
           titleStyle != oldWidget.titleStyle;
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ThemeData(
      primaryColor: Colors.blue,
      titleStyle: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      child: Scaffold(
        body: MyTitle(),
      ),
    );
  }
}

class MyTitle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final theme = ThemeData.of(context);
    return Text(
      'Привет',
      style: theme.titleStyle.copyWith(color: theme.primaryColor),
    );
  }
}

Характеристики:

  • Передаёт данные вниз по дереву виджетов
  • Избегает "prop drilling" (передача параметров через каждый уровень)
  • updateShouldNotify() определяет, нужно ли перестраивать потомков
  • Базовый механизм для state management решений (Provider, Riverpod)

Сравнительная таблица

АспектStatelessWidgetStatefulWidgetInheritedWidget
СостояниеНетДаДа (для распространения)
ИзменяемостьНетДа (через setState)Да (updateShouldNotify)
ИспользованиеСтатичный контентИнтерактивные элементыГлобальные данные
ПроизводительностьБыстроМедленнееЗависит от реализации
СложностьПростойСреднийСредний

Когда использовать каждый

StatelessWidget:

  • Кнопки, текст, иконки
  • Компоненты, которые не меняются
  • Дочерние виджеты, что получают данные через параметры

StatefulWidget:

  • Формы с user input
  • Компоненты с анимациями
  • Локальное состояние (счётчик, переключатель)

InheritedWidget:

  • Тема приложения
  • Аутентификация пользователя
  • Глобальные настройки
  • Базовые решения для state management

Практический пример со всеми тремя

class AppState extends InheritedWidget {
  final String userName;

  const AppState({
    required this.userName,
    required Widget child,
  }) : super(child: child);

  static AppState of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<AppState>()!;
  }

  @override
  bool updateShouldNotify(AppState oldWidget) {
    return userName != oldWidget.userName;
  }
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _userName = 'Guest';

  @override
  Widget build(BuildContext context) {
    return AppState(
      userName: _userName,
      child: Scaffold(
        body: UserGreeting(),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              _userName = 'John';
            });
          },
          child: Icon(Icons.edit),
        ),
      ),
    );
  }
}

class UserGreeting extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appState = AppState.of(context);
    return Text('Привет, ${appState.userName}!');
  }
}

Заключение

StatelessWidget идеален для неизменяемых элементов UI. StatefulWidget используется когда нужно управлять локальным состоянием. InheritedWidget — это способ делиться состоянием с потомками без передачи параметров. На практике часто используют Provider или Riverpod, которые строятся на InheritedWidget.