🧱 Давайте поговорим про 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(). Минимум кода, максимум контроля над состоянием и никакой архитектурной бюрократии.