Flutter BLoC Example

 

Flutter BLoC

We will use classic counter bloc app example to understand BLoC state management.

We have to know a few things first. In BLoC users interaction is taken as events and events cause change of the application, which means causes states or variables to be changed.

BLoC States

States are caused by events. In general you want to cleare your states as classes. Different states you have to delcare different classes.

These classes have to have a base class. We created these classes in app_states.dart file.

class CounterStates{
  int counter;
  CounterStates({required this.counter});
}

class InitialState extends CounterStates{
  InitialState():super(counter:0);
}

BLoC Events

Events are caused by users interactions like a button click. Events are also declared as classes. 

You must have an abstract class and that class should be extended by your events classes. For events classes you can name them anything.

We created the classes in app_events.dart file. Our abstract class name is CounterEvents

abstract class CounterEvents{}
class Increment extends CounterEvents{}
class Decrement extends CounterEvents{}

Blocs

Blocs are creating using the combination of events and states. Earlier we created CounterEvents and CounterStates class. We combine thme using a new class CounterBlocs

We created them in a new file name app_blocs.dart

class CounterBlocs extends Bloc<CounterEvents, CounterStates>{
  CounterBlocs():super(InitialState()){
    on<Increment>((event, emit){
      emit(CounterStates(counter: state.counter+1));
    });

    on<Decrement>((event, emit){
      emit(CounterStates(counter:state.counter-1));
    });
  }
}

BlocProvider

BlocProvider is the entry point of your BLoC for your app. You need to wrap MaterialApp using BlocProvider. At the same time, we need to inject CounterBlocs() class that we created.

void main(){
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_)=>CounterBlocs(),
      child: const MaterialApp(
        home: HomePage(),
      ),
    );
  }
}

BlocBuilder

BlocBuilder is used for finding events and states of the app. If you wrap your widget inside BlocBuilder, you would be able to find them. 

If you can find them, you can trigger events and change the states of the app, variables and things like that.

Most importantly, you may add new events which will trigger change of the states.

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<CounterBlocs, CounterStates>(
        builder: (context, state){
          return  Column(
              //crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  state.counter.toString(), style: const TextStyle(
                  fontSize: 30
                ),
                )    ,
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    ElevatedButton(
                        onPressed:
                        ()=>BlocProvider.of<CounterBlocs>(context).add(Increment()),
                        child: const Icon(Icons.add)
                    ),

                    const SizedBox(width: 10,),

                    ElevatedButton(
                        onPressed:
                        ()=>BlocProvider.of<CounterBlocs>(context).add(Decrement()),
                        child: const Icon(Icons.remove)
                    )
                  ],
                ),
                const SizedBox(height: 10,),
                InkWell(
                  onTap: () {
                    Navigator.push(context,
                        MaterialPageRoute(
                            builder: (context) => const SecondPage()));
                  },
                  child: Container(
                    width: 138,
                    height: 35,

                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(5),
                      color: Colors.grey,
                    ),
                    child: const Center(child: Text("click", style: TextStyle(color: Colors.white),)),
                  ),

                )
              ],
            );

        }
      ),
    );
  }
}

BlocProvider.of

Using BlocProvider.of you can find blocs and read the value of a state varaible.

class SecondPage extends StatelessWidget {
  const SecondPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final CounterBlocs counterBloc = BlocProvider.of<CounterBlocs>(context);
    return Scaffold(
      appBar: AppBar(
        title: const Text("Blocs"),
        leading: BackButton(
          onPressed: ()=>Navigator.pop(context),
        ),
      ),
      body:BlocBuilder(
          bloc: counterBloc,
          builder: ( context, state) {
            return Center(
              child: Text(counterBloc.state.counter.toString(),style: const TextStyle(
                  fontSize: 30
              ),),
            );
          })
    );
  }
}

Recent posts