← Назад к вопросам
Что такое BlocProvider и BlocBuilder?
2.0 Middle🔥 222 комментариев
#State Management#Архитектура Flutter
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
BlocProvider и BlocBuilder
BLoC (Business Logic Component) — это паттерн управления состоянием, основанный на Streams. Это альтернатива Provider и GetX.
Основная концепция BLoC
Визуально:
┌─────────────────────────┐
│ BLoC │
│ (Business Logic) │
│ │
│ Input: Sink (Events) │ ← Пользователь действует
│ Output: Stream (State)│ → UI обновляется
└─────────────────────────┘
↑ ↓
Widget Input → BlocBuilder
Структура BLoC
// 1. События (что может произойти)
class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
// 2. Состояния (текущее состояние UI)
class CounterState {
final int count;
CounterState({required this.count});
}
// 3. BLoC (обработка событий и генерация состояний)
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(count: 0)) {
// Регистрируем обработчики событий
on<IncrementEvent>(_onIncrement);
on<DecrementEvent>(_onDecrement);
}
// Обработчик события Increment
Future<void> _onIncrement(
IncrementEvent event,
Emitter<CounterState> emit,
) async {
emit(CounterState(count: state.count + 1));
}
// Обработчик события Decrement
Future<void> _onDecrement(
DecrementEvent event,
Emitter<CounterState> emit,
) async {
emit(CounterState(count: state.count - 1));
}
}
BlocProvider — провайдер BLoC
// Создание BLoC один раз
BlocProvider(
create: (context) => CounterBloc(),
child: MyWidget(),
)
// Multi — если несколько BLoCs
MultiBlocProvider(
providers: [
BlocProvider(create: (context) => CounterBloc()),
BlocProvider(create: (context) => AuthBloc()),
BlocProvider(create: (context) => ThemeBloc()),
],
child: MyApp(),
)
BlocBuilder — слушатель состояния
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text('Count: ${state.count}');
},
)
Полный пример счётчика
// События
abstract class CounterEvent {}
class IncrementPressed extends CounterEvent {}
class DecrementPressed extends CounterEvent {}
// Состояния
class CounterState {
final int count;
CounterState({required this.count});
}
// BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(count: 0)) {
on<IncrementPressed>(_onIncrement);
on<DecrementPressed>(_onDecrement);
}
Future<void> _onIncrement(
IncrementPressed event,
Emitter<CounterState> emit,
) async {
emit(CounterState(count: state.count + 1));
}
Future<void> _onDecrement(
DecrementPressed event,
Emitter<CounterState> emit,
) async {
emit(CounterState(count: state.count - 1));
}
}
// UI
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterBloc(),
child: Scaffold(
appBar: AppBar(title: Text('BLoC Counter')),
body: Center(
child: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${state.count}', style: TextStyle(fontSize: 48)),
SizedBox(height: 32),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(DecrementPressed()),
child: Icon(Icons.remove),
),
SizedBox(width: 16),
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(IncrementPressed()),
child: Icon(Icons.add),
),
],
),
],
);
},
),
),
),
);
}
}
BlocListener — реагирование на события
Используется для побочных эффектов (навигация, диалоги, снэки).
BlocListener<CounterBloc, CounterState>(
listener: (context, state) {
if (state.count == 10) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Достигли 10!')),
);
}
},
child: MyWidget(),
)
Практический пример: Получение данных
// События
abstract class UserEvent {}
class FetchUserEvent extends UserEvent {
final String userId;
FetchUserEvent({required this.userId});
}
// Состояния
abstract class UserState {}
class UserInitial extends UserState {}
class UserLoading extends UserState {}
class UserSuccess extends UserState {
final User user;
UserSuccess({required this.user});
}
class UserFailure extends UserState {
final String error;
UserFailure({required this.error});
}
// BLoC
class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepository repository;
UserBloc({required this.repository}) : super(UserInitial()) {
on<FetchUserEvent>(_onFetchUser);
}
Future<void> _onFetchUser(
FetchUserEvent event,
Emitter<UserState> emit,
) async {
emit(UserLoading());
try {
final user = await repository.getUser(event.userId);
emit(UserSuccess(user: user));
} catch (e) {
emit(UserFailure(error: e.toString()));
}
}
}
// UI
class UserScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserInitial) {
return Center(child: Text('Нажмите кнопку'));
} else if (state is UserLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is UserSuccess) {
return Center(child: Text(state.user.name));
} else if (state is UserFailure) {
return Center(child: Text('Ошибка: ${state.error}'));
}
return SizedBox();
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<UserBloc>().add(FetchUserEvent(userId: '123'));
},
child: Icon(Icons.download),
),
);
}
}
BlocBuilder vs BlocListener vs BlocConsumer
// BlocBuilder — только UI обновление
BlocBuilder<MyBloc, MyState>(
builder: (context, state) => ...,
)
// BlocListener — побочные эффекты
BlocListener<MyBloc, MyState>(
listener: (context, state) => ...,
child: ...,
)
// BlocConsumer — комбинация обоих
BlocConsumer<MyBloc, MyState>(
listener: (context, state) => ..., // Побочные эффекты
builder: (context, state) => ..., // UI обновление
)
Преимущества BLoC
- Полная разделение логики и UI — легко тестировать
- Event-driven — явная история всех действий
- Масштабируемость — подходит для больших проектов
- TypeSafe — типобезопасные события и состояния
- DevTools — отличная поддержка в Flutter DevTools
Недостатки
- Boilerplate код — много классов для простых случаев
- Кривая обучения — сложнее чем Provider
- Оверинжиниринг — для простых приложений
Когда использовать BLoC
- Большие приложения с сложной логикой
- Нужна полная история всех действий (для аналитики, логирования)
- Требуется максимальная тестируемость
- Много разработчиков в команде
Альтернативы
- Provider — проще, минимальный boilerplate
- Riverpod — современнее, тоже хороший выбор
- GetX — быстрее в разработке, но меньше контроля