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

В чём разница между 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'));

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

ПараметрCubitBLoC
ПростотаПростойСложный
Кривая обученияНизкаяВысокая
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 — это полнофункциональное решение для сложных приложений. Выбор зависит от сложности вашего приложения и требований к масштабируемости.