BLoC — vad är det, Business Logic Component i Flutter

Författare: IT Sectr Publicerad: 2026-02-19 Lästid: 7 min

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

  • Event — ingångssignal som beskriver handlingen: knapptryck, laddning av data
  • State — utgångstillstånd för UI: data laddad, fel, laddar
  • Bloc — huvudklass som tar emot Event och returnerar State via Stream
  • Cubit — förenklad version av Bloc utan Event, anropar funktioner direkt
  • BlocProvider — Flutter-widget för att injicera Bloc i widgetträdet

Vad är BLoC?

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

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.

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;
    }
  }
}

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.

Bloc och Cubit: jämförelse

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.

EgenskapBlocCubit
Event-klasserObligatoriskaBehövs inte
BoilerplateHögLåg
Spårning av handlingarVia Event-typEndast metodnamn
Passar förKomplexa scenarierEnkla tillstånd
AnalysAutomatisk via EventManuell

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 och BlocBuilder

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

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

Testa BLoC

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.

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

BLoC i produktion

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

Vad är skillnaden mellan BLoC och Provider i Flutter?

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.

Vad är Hydrated Bloc?

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.

Hur hanterar man fel i BLoC?

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.

Kan BLoC användas med andra ramverk?

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.

Vad välja: Bloc eller Cubit?

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

  • BLoC — mönster för tillståndshantering i Flutter via Event → Stream → State
  • Event — åtgärd (klick, laddning), State — reaktion (data, fel, laddar)
  • Cubit — förenklad version utan Event, upp till 50% mindre boilerplate
  • BlocProvider — injicering av Bloc i widgetträdet med automatisk close
  • BlocObserver — global övervakning av alla Bloc och Cubit i applikationen
  • Hydrated Bloc — automatisk persistens av tillstånd via Hive
  • blocTest — verktyg för modulär testning av Bloc med isolering från Flutter

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.

Diskutera projektet

Läs också