# Flutter State Management

7 min read, 1224 words flutterstatemanagementpatternbloc

Reactive Programming Streams - BLoC Patern (opens new window)

cubit is now merged into bloc library

# BLoC vs flutter_block

https://bloclibrary.dev/#/gettingstarted (opens new window)

  1. BloC Architecture
  2. BloC context
  3. BloC Testing

# Why BLoC?

App should be able to handle EVERY interaction

  • Business Logic Component , pattern created by google for presentation layer
  • App should have a state for EVERY possible Everything
    • if their is not Internet, show them
    • if data could not be fetched, show them it (re)-trying
  • STREAMS are the foundation of BLoC
    • Asynchronous code sent in parts

note

GOOD Application must have a valid STATE VALUE at all times.

A StatefulWidget does not scale to larger applications. The BLOC pattern does.

# Why Streams?

Stream<int> someStream() async* {
  for (int i = 1; i <= 10; i++>) {
    print("SENT number = " + i.toString());
    await Future.delayed(Duration(seconds: 2));
    yield i;
  }
}

void main(List<string> args) async {
  Stream<int> stream = boatStream();
  stream.listen((receivedData) {
    print("Recieved number" + receivedData.toString());
  });
}

# Cubit

  • is a special type of Stream component which updates UI on state change
  • emit event on stream using yield
  • cubit is a component based of some functions
    • functions that are not part of the stream
    • cubit only emits streams of states to UI
  • you can subscribe and listen to cubit states changes in components
  • BLoC also recieves stream of events and emits stream of states
  • To use BLoc or cubit, you first have to declare it.
difference description
Cubit streaming states + Functions events that are NOT streams
BloC streaming states + Streaming events

# BLoC Widget

  • use BlocProvider Widget when it has to be used at multiple places
    • Dependency Injection widget
    • same idea as React.contenxt Provide API
  • Wrap the EXACT part to be re-built inside the BlocBuilder

# Flutter BloC Concepts

bloc description
BlockProvider Accessable with a Widget tree, Dependency Injection in BloC Tree
BlockBuilder re build the UI on state change
BlockListener only listen for change, single time unlike BlockBuilder
BlocConsumer mixture of BlockListener and BlockProvider
  • BlockProvider are created lazily
  • to access use BlockProvider.of<myCubit>(context).myFunction();
  • Annotate required sates as @required
  • Wrap only the part yu want to update inside BlockBuilder<myCubit, myState>()
  • BlockListener<myCubit, myState>(listener: () {}) on top of BlockBuilder
    • BlocConsumer(lstener: ..., builder: ...)
    • The listener is guaranteed to only be called once for each state change unlike the builder in BlocBuilder.
  • Repository -> classes which provides dart to Data Layer DAL
    • transformations like filter, sort before passing data to BloC
  • Local vs Route BloC Access

# Steps

When to BloC?

Every dynamic feature in app should have its own BloC

  1. Define a block by overriding its methods and then initialize it by calling its super
  2. Register Events on BloC using on API
    1. define state changes in on callback function which accepts event and emit
    2. modified states changes are emitted
  3. Using the Block in UI Widgets
    1. BlockProvide creates a instance of a bloc and all it's chold have access
    2. create an instance of BlocComponent as final and then call events on it using add API
    3. wait for events to deliver a response await Future.delayed(Duration.zero)

wait for evnt-loop

await Future.delayed(Duration.zero) is added to ensure we wait for the next event-loop iteration (allowing the EventHandler to process the event).

  1. For RT subscriptions to changes, use Streams >> Futures
Future<void> main() async {
  final bloc = CounterBloc();
  final subscription = bloc.stream.listen(print); // 1
  bloc.add(Increment());
  await Future.delayed(Duration.zero);
  await subscription.cancel();
  await bloc.close();
}

# Enterprise App source organization

  1. data
    1. models
    2. repositories
    3. dataProviders
  2. business_logic
    1. bloc
    2. cubit
  3. presentation
    1. widgets
    2. pages
    3. screens
    4. animations
    5. routes
    6. Theme, ColorPallet

# questions

  • When to use cubit and when to use bloc?
    • Each feature should have a cubit or bloc to manage/control it.
    • Difference is in how they recieve information
    • cubits are cheaper than bloc
  • Should I have a BLoC for each UI componet?
    • Having multiple (many) instances of same BLoC is a terrible idea
  • What is repository in flutter?
    • communicating with external data-layers , DAL, network-calls, databases etc.
  • How to start building a Application?
    • start with appdb, or application modal
    • Application Modal should be independent from the source
  • How to structure your source code?
    • seperate directory for each layer and sub-layer
  • How to make internet connection aware mobile application?
    • connectivity_plus package

# Build context

Every block must override the mapEventToState function. This is a generator function, which accepts event and returns a stream, that notifies of state change whatever is subscribed to it. In redux world it is reducer.

  • everything in flutter is a Widget
  • every widget in flutter has a build function
  • every build method is built from a context. So Every widget has its own context
  • in flutter MyApp widget is the root of widget tree of an application
  • build content ONlY knows about its parent context, bottoms-up, there is no other way
  • new screens are pushed on widget tree and old routes are popped out from tree
  • Use Flutter devtools to visualize widget tree and context

How multiple context interact with each other?

WARNING

Never mutate and emit state from inside of BLoC. Let UI emit the events

# Hydrated Block

  • restore app-data/state from localstorage
  • fast and close to application
  • uses hive under the-hood which is blazingly fast

# Debugging BLoC

  • How to override all the onChange, onError, onTransition, onEvent methods on BLoC ?
    • onCreated
    • onClose
  • BlocObserver

BlocObserver

When we want to be able to do something in response to all Changes we can simply create our own BlocObserver.

# Data Fetching over network

data fetching in build method

Although itโ€™s convenient, itโ€™s not recommended to put an API call in a build() method.

  • Make networl call using http library using Futures is easy, but working with response is hard
  • Transform http.response --> Dart Object, using Models in repository
  • Flutter data fetching (opens new window)
  • Whent to make the netwrk call?
    • exactly once? initState
      • MyApp widget becomes stateful when app wants data from API on initial load
    • based on event emitted?
  • How to display the data on UI?
    • FutureBuilder widget
  • How to use an existing BloC on abother page? BlocProvide.value() constructor

# Use-cases

# Load a new view/page on a click

MaterialButton(
  onPressed: () {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => BlocProvider.value(
          value: existingCubit();     // NOT A new cubit
          value: BlockProvider.of<yourCubitName>(context);
          child: ....
        )
      )
    )
  }
)

# Search and filter items widget

as the user type. Use debounce feature to wait for sometime before making API call

# Best Practises

  • keep BloC in seperate file for testability
  • write BloC per feature

# Sample Repos

Subscribe to our Newsletter

If you like my work and think it was helpful kindly support my work


Buy Me A Coffee