Flutter State Management | RRTutors

Flutter State Management

We are always looking for a powerful way of state management. We knows flutter itself has provided us with state management Stateful widget

 

Flutter has different ways of estate management topics

Stateful Widget

InheritedWidget

Provider

BLoC

 

Stateful Widget

Widgets which will change its behaviour/state dynamically called stateful widgets

Stateful widgets are useful when the part of the user interface you are describing can change dynamically. User interfaces need to respond to a variety of things: The user doing something in the user interface.

Receiving data from another computer.

 

This is what Stateful Widgets are for. They store data (state) in an associated State class and they can respond when that data (state) changes as the result of the user doing something

 

Let's create a Counter app with Stateful widget

 

class MyStatefulwidget extends StatefulWidget{

 @override

 State<StatefulWidget> createState() {

   // TODO: implement createState

   return MyState();

 }

 

}

 

class MyState extends State<MyStatefulwidget>{

 int count;

 @override

 void initState() {

   // TODO: implement initState

   super.initState();

   count=0;

 }

 @override

 Widget build(BuildContext context) {

   // TODO: implement build

   return Scaffold(

     appBar: AppBar(title: Text("Statefulwidget"),backgroundColor: Colors.pink,),

     floatingActionButton: FloatingActionButton(onPressed: (){

       setState(() {

         count++;

       });

     },child: Icon(Icons.add,color: Colors.white,),backgroundColor: Colors.pink,),

     body: Container(

       child: Center(

         child: Text("Count : $count",style: TextStyle(color: Colors.pink,fontSize: 20),),

       ),

     ),

   );

 }

 

}

 

here on tap on add button every time we are updating the state by calling the  setState() method, so this will entirely rebuild the widget

This will be useful when a single widget needs to update the State.


 

InheritedWidget

Flutter provides an InheritedWidget that can define provide context to every widget below it in the tree.

InheritedWidget is a special widget that can store and retrieve data , and subcomponents can obtain stored data. Commonly used MediaQuery and Theme are inherited from InheritedWidget

 

While this is nice in theory, we can see that it takes quite a lot of code to get a basic example wired up. Fortunately, there are libraries like Bloc, Redux, and Scoped Model abstract this complexity away

Let's check the counter app with InheritedWidget

 

Create InheritedWidget

class CounterInherited extends InheritedWidget{

 

 final Map _counter={'count':0};

 

 Widget child;

 CounterInherited ({@required Widget this. child}):super(child:child);

 

 get counter=>_counter['count'];

 

 increment() {

   _counter['count']++;

 }

 

 @override

 bool updateShouldNotify(InheritedWidget oldWidget) {

   // TODO: implement updateShouldNotify

   return true;

 }

 

 static CounterInherited of(BuildContext ctx)=> ctx.inheritFromWidgetOfExactType(CounterInherited);

 

}

 

Here we are extending the class with InheritedWidget, which have override method will tell the widget to need to update state or not

 

@override

bool updateShouldNotify(InheritedWidget oldWidget) {

 // TODO: implement updateShouldNotify

 return true;

}


 

Create Child widget

Child widget will have the counter increment UI

 

class Counter extends StatefulWidget{

 @override

 State<StatefulWidget> createState() {

   // TODO: implement createState

   return CounterState();

 }

 

}

 

class CounterState extends State<Counter>{

 @override

 Widget build(BuildContext context) {

   int count=CounterInherited.of(context).counter;

 

   return Scaffold(

     appBar: AppBar(title: Text("InheritedWidget"),centerTitle: true,backgroundColor: Colors.pink,),

     floatingActionButton: FloatingActionButton(onPressed: (){

       setState((){});

       CounterInherited.of(context).increment();

     },child: Icon(Icons.add,color: Colors.white,),backgroundColor: Colors.pink,),

     body: Container(

       child: Center(

         child: Text("Count : $count",style: TextStyle(color: Colors.pink,fontSize: 20),),

       ),

     ),

   );

 }

 

}

 

This Child widget need parent widget instance to update counter value,

 This will done by static method of CounterInherited widget

 

CounterInherited.of(context)

 

Main Widget

Now create a widget which contains parent widget as Inherited widget and pass child widget of our counter widget

 

class MyInherited extends StatelessWidget{

 @override

 Widget build(BuildContext context) {

   // TODO: implement build

   return CounterInherited(

     child: Counter(),

   );

 }

 

}

void main() => runApp(MyInherited ());

 

 

BLoC

Flutter, however, brings a new reactive style that is not entirely compatible with MVC. Its design idea is to separate data from views, and render views by data mapping

 

A variation of this classical pattern has emerged from the Flutter community – BLoC


 

What is BLoC?

BLoC stands for Business Logic Components, BLoC is a method of building applications using reactive programming. This is a completely asynchronous world composed of streams

 

  • Wrap stateful components with StreamBuilder, streambuilder will listen for a stream

  • This stream comes from BLoC

  • The data in the stateful widget comes from the listening stream.

  • User interaction gestures are detected and events are generated. For example, press the button.

  • Call the function of bloc to handle this event

  • After processing in bloc, the latest data will be added to the sink of the stream.

  • StreamBuilder listens to new data, generates a new snapshot, and calls the build method again

  • Widget is rebuilt

 

Example

Here we coding a simple counter application with BLoC 

 

This Example show the Number counts in the first page, in the second page we are increase the counter number, this will reflect in the fistpage

For this we are going to create app with below steps

 

Create bloc model

CountBLoC

class CountBLoC{

 

 int _count = 0;

 var _countController = StreamController<int>.broadcast();

 

 Stream<int> get stream => _countController.stream;

 int get value => _count;

 

 addCount() {

   _countController.sink.add(++_count);

 }

 

 dispose() {

   _countController.close();

 }

}

 

Create Provider

 

class BlocProvider extends InheritedWidget{

 

 CountBLoC bLoC = CountBLoC();

 

 BlocProvider({Key key, Widget child}) : super(key: key, child: child);

 

 @override

 bool updateShouldNotify(InheritedWidget oldWidget) {

   // TODO: implement updateShouldNotify

   return true;

 }

 

 static CountBLoC of(BuildContext context) =>

     (context.inheritFromWidgetOfExactType(BlocProvider) as BlocProvider).bLoC;

}

 

Create First Page 

This Page will show the number counts, for this we are accessing the data with streambuilder 

 

class CountPage extends StatelessWidget{

 @override

 Widget build(BuildContext context) {

   final bloc = BlocProvider.of(context);

   return Scaffold(

     backgroundColor: Colors.white,

     appBar: AppBar(

       title: Text('Counter Page',),

       backgroundColor: Colors.pink,

     ),

     body: Center(

       child: StreamBuilder<int>(

           stream: bloc.stream,

           initialData: bloc.value,

           builder: (BuildContext context, AsyncSnapshot<int> snapshot) {

             return Text(

               'Number Counts : ${snapshot.data}',style: TextStyle(color: Colors.pink,fontSize: 20),

             );

           }),

     ),

     floatingActionButton: FloatingActionButton(

       backgroundColor: Colors.pink,

         child: Icon(Icons.add,color: Colors.white,),

         onPressed: () =>

             Navigator.of(context).push(MaterialPageRoute(builder: (context) => DisplayPage()))),

   );

 }

}


 

Create Second page

This Page will increase the count by tap on button. With calling the addCount function will increase the count value

 

class DisplayPage extends StatelessWidget{

 @override

 Widget build(BuildContext context) {

   // TODO: implement build

   final bloc = BlocProvider.of(context);

   print('build');

   return Scaffold(

     backgroundColor: Colors.white,

     appBar: AppBar(

       title: Text('Update Count'),

       backgroundColor: Colors.pink,

     ),

     body: Center(

       child: StreamBuilder(

           stream: bloc.stream,

           initialData: bloc.value,

           builder: (context, snapshot) => Center(

             child: Text( " Counter : ${snapshot.data} \nIncreate Count by Button tap", style: TextStyle(color: Colors.pink,fontSize: 20),textAlign: TextAlign.center,),

           )),

     ),

     floatingActionButton: FloatingActionButton(

       onPressed: () => bloc.addCount(),

       backgroundColor: Colors.pink,

       child: Icon(Icons.add,color: Colors.white,),

     ),

   );

 }

 

}




 

Now It’s time to check out Main Page

Here we are using the Provider to load the child widgets to Inherited widget.

 

class MyBloc extends StatelessWidget {

 @override

 Widget build(BuildContext context) {

   return BlocProvider(

     child: MaterialApp(

       title: 'BLoC',

       theme: ThemeData.dark(),

       home: CountPage(),

     ),

   );

 }

}

Advertisements