BLoC (Business Logic Component) — vzor řízení stavu pro Flutter, představený společností Google v roce 2018 na DartConf. BLoC odděluje obchodní logiku od uživatelského rozhraní prostřednictvím reaktivních toků (Stream): UI odesílá Event, BLoC jej zpracuje a vrací nový State prostřednictvím Stream. Podle údajů pub.dev, balíček flutter_bloc nasbíral více než 11 tisíc lajků a používá se v tisících Flutter aplikací.
Hlavní body
BLoC (Business Logic Component) — architektonický vzor pro Flutter, ve kterém je obchodní logika vyčleněna do samostatné třídy, izolované od UI. BLoC přijímá vstupní data prostřednictvím toku událostí (Event) a vytváří výstupní data prostřednictvím toku stavů (State). Prezentační vrstva (Widget) se pouze přihlásí k odběru toku State a zobrazuje UI, aniž by kdy přímo spouštěla obchodní logiku.
Koncepce BLoC je založena na reaktivním programování a vzoru Observer. Každá komponenta BLoC je samostatný modul s jasnou smlouvou: známá je sada Event (co se může stát) a sada State (co může být zobrazeno). Vývojář nemůže "náhodně" změnit stav z UI — pouze prostřednictvím konkrétního Event. To činí kód předvídatelným a testovatelným.
Podle průzkumu Flutter Community 2025 zaujímá BLoC druhé místo v popularitě mezi řešeními řízení stavu ve Flutter po Provider. Hlavní výhody: přísná typizace, izolace logiky, vestavěná podpora Stream, bohatý ekosystém nástrojů (BlocProvider, BlocListener, BlocSelector).
Architektura BLoC je postavena kolem tří entit: Event (vstup), Bloc (zpracovatel) a State (výstup). Widget odesílá Event prostřednictvím metody add(). Bloc přijímá Event v metodě mapEventToState nebo on<Event>, provádí obchodní logiku a vytváří nový State pomocí yield. Widget přijímá State prostřednictvím Stream a překresluje se.
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
@override
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield state + 1;
} else if (event is Decrement) {
yield state - 1;
}
}
}Bezpečnost typů: Bloc je parametrizován dvěma typy — Event a State. Kompilátor Dart kontroluje, že Widget volá pouze deklarované Event, a Bloc vrací pouze deklarované State. Chyby běhu typu "Neznámá akce" jsou vyloučeny.
Close a Dispose: Bloc implementuje rozhraní Closeable. Při zničení widgetu Bloc automaticky uzavře Stream prostřednictvím metody close(). Úniky reaktivních odběrů jsou nemožné — BlocProvider spravuje životní cyklus Bloc a váže jej na route nebo stránku.
Cubit — zjednodušená implementace Bloc bez Event, představená v balíčku flutter_bloc 6.0. Cubit deklaruje metody přímo místo tříd Event: increment(), fetchData(). Interně Cubit používá stejný mechanismus založený na Stream, ale skrývá vrstvu Event. To snižuje boilerplate o 40-50 % pro jednoduché scénáře.
| Vlastnost | Bloc | Cubit |
|---|---|---|
| Třídy Event | Povinné | Nejsou potřeba |
| Boilerplate | Vysoký | Nízký |
| Sledování akcí | Prostřednictvím typu Event | Pouze název metody |
| Vhodné pro | Složité scénáře | Jednoduché stavy |
| Analytika | Automatická prostřednictvím Event | Ruční |
Kdy zvolit Cubit: stav s 2-3 variantami (loading, loaded, error), jednoduché formuláře, počítadla, UI stavy (otevřeno/zavřeno). Kdy Bloc: složitá obchodní logika s mnoha akcemi: dokončení objednávky, autorizace, synchronizace dat. Bloc poskytuje detailní sledování každé akce prostřednictvím Event — každé volání je protokolováno v BlocObserver.
BlocObserver — globální pozorovatel sledující všechny Bloc a Cubit v aplikaci. Umožňuje protokolování Event, State, chyb a přechodů. Stačí připojit jednu instanci: Bloc.observer = AppBlocObserver(), a celé sledování stavu aplikace je k dispozici centralizovaně.
BlocProvider — InheritedWidget z flutter_bloc, který poskytuje Bloc podřízeným widgetům. Při inicializaci widgetu BlocProvider vytvoří Bloc a při zničení — jej automaticky uzavře pomocí close(). BlocProvider může být umístěn na úrovni MaterialApp (globální Bloc) nebo na úrovni konkrétní route (lokální Bloc).
BlocProvider(
create: (context) => CounterBloc(),
child: Column(
children: [
BlocBuilder<CounterBloc, int>(
builder: (context, state) => Text('$state'),
),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(Increment()),
child: Text('+'),
),
],
),
)BlocBuilder — widget, který přestavuje UI při každém novém State. BlocListener — pro vedlejší efekty (jednorázové zpracování State bez přestavby UI): zobrazení SnackBar, navigace na jinou obrazovku. BlocConsumer — kombinace Builder a Listener pro případy, kdy je potřeba jak přestavba, tak vedlejší efekt. BlocSelector — pro selektivní přestavbu pouze při změně konkrétního pole State.
MultiBlocProvider — widget pro vnořené BlocProvider bez zvyšování úrovně vnoření. Flutter aplikace s 10-15 Bloc používá MultiBlocProvider na kořenové úrovni pro registraci všech Bloc dostupných v celé aplikaci: AuthenticationBloc, CartBloc, SettingsBloc.
BLoC se testuje izolovaně bez Flutter widgetů. Stačí importovat Dart balíček flutter_test a balíček bloc_test. Testovací scénář: vytvořit Bloc, přidat Event, zkontrolovat State. blocTest — nástroj automatizující sekvenci: build → act → expect.
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
)Mocking: BLoC závislý na repozitáři nebo API se testuje s mocky pomocí mocktail. Repozitář je mockován na úrovni abstrakce, Bloc získává mockované závislosti prostřednictvím konstruktoru. Hydrated Bloc — rozšíření pro automatické ukládání/obnovování stavu v lokálním úložišti. Testuje se s HydratedBlocStorage a dočasným souborovým úložištěm.
Složky a soubory: typická struktura Flutter projektu s BLoC: bloc/counter_bloc.dart, bloc/counter_event.dart, bloc/counter_state.dart. Pro 30+ obrazovek se doporučuje seskupení podle funkcí: features/auth/bloc/, features/cart/bloc/. Každý Bloc — samostatný soubor, každý Event a State — buď v samostatných souborech, nebo v jednom souboru s Bloc.
Výkon: BLoC nevytváří režii na prázdné Streamy. BlocBuilder používá buildWhen pro filtrování přestaveb — widget se aktualizuje pouze při změně konkrétní podmínky. Close zaručuje, že neaktivní Bloc nespotřebovávají paměť. Podle Flutter DevTools přidává BLoC méně než 1 % k velikosti balíčku.
Migrace z Provider: BLoC snadno koexistuje s Provider v jednom projektu. Postupná migrace: nejprve se nahradí nejsložitější Provider za Bloc, poté zbytek. BlocProvider je kompatibilní se stromem Provider: staré widgety mohou používat Provider, nové — BlocProvider, v jedné aplikaci.
Často kladené otázky
BLoC používá Event + Stream pro izolaci obchodní logiky a přísnou typizaci. Provider — obal nad InheritedWidget pro jednoduché vkládání závislostí a ChangeNotifier. BLoC je vhodnější pro složité scénáře s mnoha stavy, Provider — pro lokální UI stav. BLoC vyžaduje více boilerplate, ale poskytuje úplnou sledovatelnost prostřednictvím Event.
Hydrated Bloc — rozšíření z balíčku hydrated_bloc, které automaticky ukládá poslední State do lokálního úložiště (ve výchozím nastavení Hive). Při restartu aplikace Bloc obnoví uložený stav namísto počátečního. To řeší problém perzistence bez ručního volání ukládání: přihlášení, košík, nastavení se ukládají automaticky mezi relacemi.
Chyba v BLoC je zpracována pomocí try-catch uvnitř mapEventToState nebo on<Event>. Při chybě Bloc vrátí stav chyby: yield LoadError(error.message). Na UI BlocListener nebo BlocConsumer zkontroluje State na typ chyby a zobrazí SnackBar nebo dialog. BlocObserver globálně protokoluje všechny neošetřené výjimky.
BLoC — vzor specifický pro Flutter, protože používá Dart Stream a Flutter widgety. Koncept Event → Bloc → State lze adaptovat pro AngularDart a Server-side Dart, ale hlavní ekosystém (BlocProvider, BlocBuilder, BlocObserver) je vázán na Flutter. Pro React Native použijte Redux nebo MobX, pro SwiftUI — Combine + MVVM.
Cubit — pro jednoduché stavy (počítadlo, toggle, formulář se 2-3 poli). Bloc — pro složitou logiku (kanál novinek, dokončení objednávky, autorizace). Hlavní pravidlo: pokud je vyžadováno sledování každé akce (Event) pro analytiku nebo ladění — Bloc. Pokud stačí metody měnící stav — Cubit. Oba vzory koexistují v jednom projektu.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.