← Назад к вопросам
В чем разница между Stateful и Stateless?
1.0 Junior🔥 211 комментариев
#State Management
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между Stateful и Stateless виджетами
StatelessWidget и StatefulWidget — это два основных типа виджетов в Flutter, которые различаются по способности управлять и изменять своё состояние.
StatelessWidget (Без состояния)
StatelessWidget — это неизменяемый виджет, который не имеет внутреннего состояния и не может измениться во время его жизненного цикла.
// Простой StatelessWidget
class GreetingWidget extends StatelessWidget {
final String name;
final int age;
const GreetingWidget({
required this.name,
required this.age,
});
@override
Widget build(BuildContext context) {
return Center(
child: Text('Hello, $name! You are $age years old.'),
);
}
}
// Использование
GreetingWidget(name: 'Alice', age: 25)
Характеристики StatelessWidget:
- Неизменяемый — свойства не меняются после создания
- Быстрый — Flutter может оптимизировать рендеринг
- Просто тестировать — поведение полностью определено параметрами
- Нет жизненного цикла — просто build() и готово
- Никогда не перестраивается — если параметры не изменились
// Примеры StatelessWidget из Material Design
Text('Hello')
Icon(Icons.home)
Button(onPressed: () => {})
Container()
Row(), Column()
Scaffold()
StatefulWidget (С состоянием)
StatefulWidget — это виджет, который может изменяться во время жизненного цикла. Состояние хранится в связанном классе State.
// StatefulWidget - сам виджет неизменяемый
class CounterWidget extends StatefulWidget {
final String title;
const CounterWidget({required this.title});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
// State - здесь живёт изменяемое состояние
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0; // Это состояние
void _increment() {
setState(() {
_counter++; // setState() уведомляет Flutter о изменении
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('${widget.title}: $_counter'),
ElevatedButton(
onPressed: _increment,
child: Text('Increment'),
),
],
);
}
}
// Использование
CounterWidget(title: 'My Counter')
Характеристики StatefulWidget:
- Изменяемый — может менять своё состояние
- Сложнее — нужна связь между виджетом и State
- Имеет жизненный цикл — initState(), build(), dispose()
- setState() — уведомляет Flutter о изменении
- Требует больше ресурсов — чем StatelessWidget
Жизненный цикл StatefulWidget
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
// Вызывается один раз при создании State
// Используй для инициализации переменных
// Инициализация контроллеров, подписок, загрузка данных
super.initState();
print('initState called');
}
@override
void didUpdateWidget(MyWidget oldWidget) {
// Вызывается, когда родитель перестроил виджет с новыми параметрами
// Сравниваются oldWidget и widget
super.didUpdateWidget(oldWidget);
print('didUpdateWidget called');
}
@override
Widget build(BuildContext context) {
// Вызывается при initState() и после setState()
// Должен быть чистым - без побочных эффектов
return Container();
}
@override
void deactivate() {
// Вызывается когда State удаляется из дерева виджетов
print('deactivate called');
super.deactivate();
}
@override
void dispose() {
// Вызывается в конце жизненного цикла
// Очистка ресурсов: закрыть потоки, отписаться от подписок
print('dispose called');
super.dispose();
}
}
Сравнение
| Аспект | StatelessWidget | StatefulWidget |
|---|---|---|
| Состояние | Нет | Да |
| Изменяемость | Неизменяемый | Изменяемый |
| Производительность | Быстрее | Медленнее |
| Сложность | Простой | Сложнее |
| Жизненный цикл | Простой | Длинный |
| setState() | Не нужен | Используется |
| Тестирование | Проще | Сложнее |
| Использование | 80% приложения | 20% приложения |
Практические примеры
Когда использовать StatelessWidget:
// Отображение статического текста
class UserCard extends StatelessWidget {
final String name;
final String email;
const UserCard({
required this.name,
required this.email,
});
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
Text(name),
Text(email),
],
),
);
}
}
// Переиспользуемый UI компонент
class GradientButton extends StatelessWidget {
final String label;
final VoidCallback onPressed;
const GradientButton({
required this.label,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Colors.blue, Colors.purple]),
),
child: ElevatedButton(
onPressed: onPressed,
child: Text(label),
),
);
}
}
Когда использовать StatefulWidget:
// Форма с валидацией
class LoginForm extends StatefulWidget {
@override
State<LoginForm> createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
late TextEditingController _emailController;
late TextEditingController _passwordController;
@override
void initState() {
super.initState();
_emailController = TextEditingController();
_passwordController = TextEditingController();
}
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
void _login() {
// Логика входа
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(controller: _emailController),
TextField(controller: _passwordController),
ElevatedButton(
onPressed: _login,
child: Text('Login'),
),
],
);
}
}
// Анимация
class RotatingBox extends StatefulWidget {
@override
State<RotatingBox> createState() => _RotatingBoxState();
}
class _RotatingBoxState extends State<RotatingBox> with TickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 2),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RotationTransition(
turns: _controller,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
}
}
Лучшие практики
- Используй StatelessWidget по умолчанию — он проще и быстрее
- Переводи StatefulWidget в StatelessWidget когда больше не нужно состояние
- Правильно очищай ресурсы в dispose() — отписывайся от подписок, закрывай потоки
- Не передавай сложное состояние через параметры — используй Provider или Riverpod
- Минимизируй setState() — он перестраивает весь виджет и его потомков
Правило: если виджету не нужно менять состояние — используй StatelessWidget. Это проще, быстрее и надёжнее.