BLoC — co to je, Business Logic Component ve Flutter

Autor: IT Sectr Publikováno: 2026-02-19 Doba čtení: 7 min

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

  • Event — vstupní signál popisující akci: stisk tlačítka, načítání dat
  • State — výstupní stav UI: data načtena, chyba, načítání
  • Bloc — hlavní třída přijímající Event a vracející State prostřednictvím Stream
  • Cubit — zjednodušená verze Bloc bez Event, volající funkce přímo
  • BlocProvider — Flutter widget pro vložení Bloc do stromu widgetů

Co je BLoC?

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: Event → Bloc → State

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.

Dart
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.

Bloc a Cubit: srovnání

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.

VlastnostBlocCubit
Třídy EventPovinnéNejsou potřeba
BoilerplateVysokýNízký
Sledování akcíProstřednictvím typu EventPouze název metody
Vhodné proSložité scénářeJednoduché stavy
AnalytikaAutomatická prostřednictvím EventRuč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 a BlocBuilder

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).

Dart
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.

Testování BLoC

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.

Dart
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.

BLoC v produkci

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

Čím se BLoC liší od Provider ve Flutter?

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.

Co je Hydrated Bloc?

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.

Jak zpracovávat chyby v BLoC?

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.

Lze BLoC použít s jinými frameworky?

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.

Co vybrat: Bloc nebo Cubit?

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í

  • BLoC — vzor řízení stavu Flutter prostřednictvím Event → Stream → State
  • Event — akce (kliknutí, načtení), State — reakce (data, chyba, načítání)
  • Cubit — zjednodušená verze bez Event, až o 50 % méně boilerplate
  • BlocProvider — vložení Bloc do stromu widgetů s automatickým close
  • BlocObserver — globální monitorování všech Bloc a Cubit v aplikaci
  • Hydrated Bloc — automatická perzistence stavu prostřednictvím Hive
  • blocTest — nástroj pro modulární testování Bloc s izolací od Flutter

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í.

Prodiskutovat projekt

Přečtěte si také