BLoC (Business Logic Component) — mönster för tillståndshantering för Flutter, presenterat av Google 2018 på DartConf. BLoC separerar affärslogik från användargränssnittet genom reaktiva flöden (Stream): UI skickar en Event, BLoC bearbetar den och returnerar ett nytt State via Stream. Enligt data från pub.dev har flutter_bloc-paketet samlat över 11 tusen likes och används i tusentals Flutter-applikationer.
Huvudpunkter
BLoC (Business Logic Component) — arkitekturmönster för Flutter där affärslogiken är placerad i en separat klass, isolerad från UI. BLoC tar emot indata via en ström av händelser (Event) och producerar utdata via en ström av tillstånd (State). Presentationslagret (Widget) prenumererar bara på State-strömmen och visar UI, utan att någonsin direkt utföra affärslogik.
BLoC-konceptet är baserat på reaktiv programmering och Observer-mönstret. Varje BLoC-komponent är en separat modul med ett tydligt kontrakt: uppsättningen Event (vad som kan hända) och uppsättningen State (vad som kan visas) är kända. Utvecklaren kan inte "av misstag" ändra tillståndet från UI — bara genom en specifik Event. Detta gör koden förutsägbar och testbar.
Enligt Flutter Community 2025-undersökningen ligger BLoC på andra plats i popularitet bland lösningar för tillståndshantering i Flutter efter Provider. Huvudsakliga fördelar: strikt typning, isolering av logik, inbyggt stöd för Stream, rikt ekosystem av verktyg (BlocProvider, BlocListener, BlocSelector).
BLoC-arkitektur är byggd kring tre enheter: Event (ingång), Bloc (processor) och State (utgång). Widget skickar Event via metoden add(). Bloc tar emot Event i metoden mapEventToState eller on<Event>, utför affärslogik och producerar ett nytt State via yield. Widget tar emot State via Stream och ritas om.
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;
}
}
}Typsäkerhet: Bloc är parametriserad med två typer — Event och State. Dart-kompilatorn kontrollerar att Widget bara anropar deklarerade Event och att Bloc bara returnerar deklarerade State. Körningsfel av typen "Okänd åtgärd" är uteslutna.
Close och Dispose: Bloc implementerar gränssnittet Closeable. När widgeten förstörs stänger Bloc automatiskt Stream via metoden close(). Läckor av reaktiva prenumerationer är omöjliga — BlocProvider hanterar Bloc:ens livscykel och kopplar den till en route eller sida.
Cubit — förenklad implementering av Bloc utan Event, introducerad i flutter_bloc 6.0-paketet. Cubit deklarerar metoder direkt istället för Event-klasser: increment(), fetchData(). Internt använder Cubit samma Stream-baserade mekanism men döljer Event-lagret. Detta minskar boilerplate med 40-50% för enkla scenarier.
| Egenskap | Bloc | Cubit |
|---|---|---|
| Event-klasser | Obligatoriska | Behövs inte |
| Boilerplate | Hög | Låg |
| Spårning av handlingar | Via Event-typ | Endast metodnamn |
| Passar för | Komplexa scenarier | Enkla tillstånd |
| Analys | Automatisk via Event | Manuell |
När välja Cubit: tillstånd med 2-3 varianter (loading, loaded, error), enkla formulär, räknare, UI-tillstånd (öppen/stängd). När Bloc: komplex affärslogik med flera åtgärder: beställning, autentisering, datasynkronisering. Bloc ger detaljerad spårbarhet av varje åtgärd via Event — varje anrop loggas i BlocObserver.
BlocObserver — global observatör som spårar alla Bloc och Cubit i applikationen. Möjliggör loggning av Event, State, fel och övergångar. Det räcker att ansluta en instans: Bloc.observer = AppBlocObserver(), och hela tillståndsspårningen av applikationen är tillgänglig centralt.
BlocProvider — InheritedWidget från flutter_bloc som tillhandahåller Bloc till underordnade widgets. Vid initiering av widgeten skapar BlocProvider en Bloc, och vid förstöring — stängs den automatiskt via close(). BlocProvider kan placeras på MaterialApp-nivå (global Bloc) eller på nivån för en specifik route (lokal 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 som bygger om UI vid varje ny State. BlocListener — för sidoeffekter (engångsbearbetning av State utan ombyggnad av UI): visa SnackBar, navigera till en annan skärm. BlocConsumer — kombination av Builder och Listener för fall där både ombyggnad och sidoeffekt behövs. BlocSelector — för selektiv ombyggnad endast när ett specifikt fält i State ändras.
MultiBlocProvider — widget för nästlade BlocProvider utan att öka nästlingsnivån. En Flutter-applikation med 10-15 Bloc använder MultiBlocProvider på rotnivå för registrering av alla Bloc som är tillgängliga i hela applikationen: AuthenticationBloc, CartBloc, SettingsBloc.
BLoC testas isolerat utan Flutter-widgets. Det räcker att importera Dart-paketet flutter_test och paketet bloc_test. Testscenario: skapa en Bloc, lägg till en Event, kontrollera State. blocTest — verktyg som automatiserar sekvensen: build → act → expect.
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
)Mockning: BLoC som är beroende av ett repository eller API testas med mockar via mocktail. Repositoryt mockas på abstraktionsnivå, Bloc får mockade beroenden via konstruktorn. Hydrated Bloc — tillägg för automatisk sparande/återställning av tillstånd i lokal lagring. Testas med HydratedBlocStorage och temporär fillagring.
Mappar och filer: typisk struktur för ett Flutter-projekt med BLoC: bloc/counter_bloc.dart, bloc/counter_event.dart, bloc/counter_state.dart. För 30+ skärmar rekommenderas gruppering efter funktion: features/auth/bloc/, features/cart/bloc/. Varje Bloc — separat fil, varje Event och State — antingen i separata filer eller i en fil med Bloc.
Prestanda: BLoC skapar inte overhead på tomma Streams. BlocBuilder använder buildWhen för filtrering av ombyggnader — widgeten uppdateras endast när ett specifikt villkor ändras. Close garanterar att inaktiva Bloc inte förbrukar minne. Enligt Flutter DevTools lägger BLoC till mindre än 1% till paketstorleken.
Migrering från Provider: BLoC samexisterar enkelt med Provider i samma projekt. Stegvis migrering: först ersätts de mest komplexa Provider med Bloc, sedan resten. BlocProvider är kompatibel med Provider-trädet: gamla widgets kan använda Provider, nya — BlocProvider, i samma applikation.
Vanliga frågor
BLoC använder Event + Stream för isolering av affärslogik och strikt typning. Provider — ett omslag kring InheritedWidget för enkel beroendeinjektion och ChangeNotifier. BLoC passar bättre för komplexa scenarier med flera tillstånd, Provider — för lokalt UI-tillstånd. BLoC kräver mer boilerplate men ger full spårbarhet via Event.
Hydrated Bloc — tillägg från paketet hydrated_bloc som automatiskt sparar det senaste State i lokal lagring (som standard Hive). Vid omstart av applikationen återställer Bloc det sparade tillståndet istället för det ursprungliga. Detta löser persistentproblemet utan manuellt sparanrop: inloggning, varukorg, inställningar sparas automatiskt mellan sessioner.
Ett fel i BLoC hanteras via try-catch inuti mapEventToState eller on<Event>. Vid fel returnerar Bloc ett feltillstånd: yield LoadError(error.message). På UI kontrollerar BlocListener eller BlocConsumer State för feltyp och visar en SnackBar eller dialogruta. BlocObserver loggar globalt alla ohanterade undantag.
BLoC — Flutter-specifikt mönster, eftersom det använder Dart Stream och Flutter-widgets. Konceptet Event → Bloc → State kan anpassas för AngularDart och Server-side Dart, men huvudekosystemet (BlocProvider, BlocBuilder, BlocObserver) är bundet till Flutter. För React Native använd Redux eller MobX, för SwiftUI — Combine + MVVM.
Cubit — för enkla tillstånd (räknare, toggle, formulär med 2-3 fält). Bloc — för komplex logik (nyhetsflöde, beställning, autentisering). Huvudregel: om spårning av varje åtgärd (Event) behövs för analys eller felsökning — Bloc. Om metoder som ändrar tillstånd är tillräckliga — Cubit. Båda mönstren samexisterar i samma projekt.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också