🧱 Давайте поговорим про Cubit во Flutter

Cubit — это облегченная версия архитектурного паттерна BLoC из библиотеки flutter_bloc. Его главная задача — забрать на себя бизнес-логику и полностью изолировать её от UI (верстки).

Суть проста: UI не знает, откуда берутся данные, он просто дергает методы Cubit. Cubit крутит логику и выплевывает обновленное состояние, на которое подписан UI.


⚙️ Как это устроено на практике

Вместо дефолтных счетчиков Cubit, которые не встречаются в реальных проектах, разберем нормальный коммерческий подход с иммутабельным (immutable) стейтом.

1. Создаем состояние (State)

class CounterState { final int value; final bool isLoading;

const CounterState({required this.value, this.isLoading = false});

CounterState copyWith({int? value, bool? isLoading}) { return CounterState( value: value ?? this.value, isLoading: isLoading ?? this.isLoading, ); } }

2. Создаем сам Cubit

class CounterCubit extends Cubit { // Задаем начальное состояние через super CounterCubit() : super(const CounterState(value: 0));

void increment() { // state — это текущее состояние класса // emit() — синхронно заменяет старый стейт на новый emit(state.copyWith(value: state.value + 1)); } }

3. Подключаем к UI и вызываем методы

Чтобы перерисовать экран, мы заворачиваем виджет в BlocBuilder, а методы дергаем через context.read():

// Слушаем изменения стейта BlocBuilder( builder: (context, state) { if (state.isLoading) return const CircularProgressIndicator(); return Text('${state.value}'); }, );

// Где-то по нажатию на кнопку: context.read().increment();

Важно помнить: метод emit() под капотом всегда сравнивает старый стейт с новым через оператор равенства (==). Если поля объекта не изменились, Cubit проигнорирует вызов и не будет вхолостую перерисовывать UI. Поэтому стейты лучше наследовать от Equatable или генерировать через Freezed.


🎯 Когда использовать Cubit, а когда BLoC?

  • StatefulWidget ──> Оставляем для локального UI-состояния (открыть/закрыть шторку, подсветить кнопку, хранить фокус в текстовом поле).
  • Cubit ──> Используем для 90% стандартных задач приложения (загрузка списков, пагинация, авторизация, формы). Здесь нет лишнего event-слоя, кодовая база чистая и линейная.
  • BLoC ──> Подключаем только тогда, когда логика требует сложной фильтрации потоков событий (например, задержка debounceTime для живого поиска в баре, чтобы не спамить сервер при каждом вводе символа).

🏁 Итог

Cubit — это инструмент прямого действия: вызвал метод ──> выполнил логику ──> сделал emit(). Минимум кода, максимум контроля над состоянием и никакой архитектурной бюрократии.