← Назад к вопросам
В чём разница между BLoC и Cubit?
2.3 Middle🔥 222 комментариев
#State Management#Архитектура Flutter
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
BLoC vs Cubit в Flutter
BLoC и Cubit — это два подхода к управлению состоянием приложения Flutter. Оба входят в экосистему bloc пакета, но отличаются по сложности и функциональности.
Cubit — простой подход
Cubit (Control Unit Business Logic) — это упрощённая версия BLoC, которая использует функции вместо потоков событий.
import 'package:flutter_bloc/flutter_bloc.dart';
// State классы
class CounterState {
final int count;
CounterState(this.count);
}
// Cubit
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(CounterState(0));
void increment() => emit(CounterState(state.count + 1));
void decrement() => emit(CounterState(state.count - 1));
}
// Использование
BlocBuilder<CounterCubit, CounterState>(
builder: (context, state) {
return Column(
children: [
Text('Count: ${state.count}'),
ElevatedButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: Text('Increment'),
),
],
);
},
)
BLoC — мощный подход
BLoC (Business Logic Component) — это сложная система, которая управляет потоками событий.
import 'package:flutter_bloc/flutter_bloc.dart';
// Events
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
// State
class CounterState {
final int count;
CounterState(this.count);
}
// BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(0)) {
// Регистрируем обработчики событий
on<IncrementEvent>((event, emit) {
emit(CounterState(state.count + 1));
});
on<DecrementEvent>((event, emit) {
emit(CounterState(state.count - 1));
});
}
}
// Использование
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Column(
children: [
Text('Count: ${state.count}'),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
child: Text('Increment'),
),
],
);
},
)
Ключевые различия
1. API вызовов
Cubit:
// Прямые методы
cubit.increment();
cubit.decrement();
BLoC:
// События
bloc.add(IncrementEvent());
bloc.add(DecrementEvent());
2. Структура
Cubit:
class MyState {}
class MyCubit extends Cubit<MyState> {
MyCubit() : super(MyState());
void myMethod() => emit(MyState()); // Прямой вызов
}
BLoC:
abstract class MyEvent {}
class MyEventAction extends MyEvent {}
class MyState {}
class MyBloc extends Bloc<MyEvent, MyState> {
MyBloc() : super(MyState()) {
on<MyEventAction>((event, emit) => emit(MyState()));
}
}
3. Сложность асинхронности
Cubit (проще):
class UserCubit extends Cubit<UserState> {
final UserRepository userRepository;
UserCubit(this.userRepository) : super(UserInitial());
Future<void> fetchUser(String id) async {
emit(UserLoading());
try {
final user = await userRepository.getUser(id);
emit(UserLoaded(user));
} catch (e) {
emit(UserError(e.toString()));
}
}
}
// Использование
cubit.fetchUser('123');
BLoC (мощнее):
abstract class UserEvent {}
class FetchUserEvent extends UserEvent {
final String id;
FetchUserEvent(this.id);
}
class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepository userRepository;
UserBloc(this.userRepository) : super(UserInitial()) {
on<FetchUserEvent>(
(event, emit) async {
emit(UserLoading());
try {
final user = await userRepository.getUser(event.id);
emit(UserLoaded(user));
} catch (e) {
emit(UserError(e.toString()));
}
},
transformer: throttleDroppable(Duration(seconds: 1)),
);
}
}
// Использование
bloc.add(FetchUserEvent('123'));
Сравнение в таблице
| Параметр | Cubit | BLoC |
|---|---|---|
| Простота | Простой | Сложный |
| Кривая обучения | Низкая | Высокая |
| API | Методы | События |
| Testability | Хорошо | Отлично |
| Масштабируемость | Средняя | Высокая |
| Трансформеры | Нет | Есть (throttle, debounce) |
| Middleware | Нет | Можно добавить |
| Документация | Хорошая | Отличная |
Практические примеры
Пример 1: Cubit для счётчика
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CounterCubit(),
child: Scaffold(
body: BlocBuilder<CounterCubit, int>(
builder: (context, count) => Text('$count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: Icon(Icons.add),
),
),
);
}
}
Пример 2: BLoC с трансформером (debounce)
class SearchBloc extends Bloc<SearchEvent, SearchState> {
final SearchRepository repository;
SearchBloc(this.repository) : super(SearchInitial()) {
on<SearchQueryChanged>(
(event, emit) async {
emit(SearchLoading());
try {
final results = await repository.search(event.query);
emit(SearchSuccess(results));
} catch (e) {
emit(SearchError(e.toString()));
}
},
// Debounce: ждёт 500ms без новых событий
transformer: debounceDroppable(Duration(milliseconds: 500)),
);
}
}
Когда использовать
Используй Cubit когда:
- Простое управление состоянием
- Старт нового проекта
- Команда привыкла к простоте
- Нет необходимости в трансформерах
Используй BLoC когда:
- Сложное управление состоянием
- Большой проект с множеством подсистем
- Нужны трансформеры (debounce, throttle)
- Требуется высокая тестируемость
- Множество связанных событий
Миграция Cubit → BLoC
// Было (Cubit)
class MyState {}
class MyCubit extends Cubit<MyState> {
void myMethod() => emit(MyState());
}
// Стало (BLoC)
abstract class MyEvent {}
class MyEventAction extends MyEvent {}
class MyState {}
class MyBloc extends Bloc<MyEvent, MyState> {
MyBloc() : super(MyState()) {
on<MyEventAction>((event, emit) => emit(MyState()));
}
}
Вывод
Cubit — это упрощённый BLoC для простых случаев. BLoC — это полнофункциональное решение для сложных приложений. Выбор зависит от сложности вашего приложения и требований к масштабируемости.