Skip to main content

How to use controller to manage state from outside of a StatefulWidget in Flutter

 A stateful widget is a widget with mutable state and rebuild itself upon changing the state. There are several state management approaches to manage state as specified on flutter.dev. It is quite easy to update its state from inside using the setState method but if we would like to update it from outside then we have to use one of the available packages. 

Today i am going to show you that we can also use controllers to manage state of a stateful widget from outside just like TextEditingController is used in case of TextField or a TextFormField. This approach is also suitable if we are creating a package and don't want to use other state management packages as dependencies.


Let's modify the default increment app that the flutter plugin generates.


First create a controller class as follows:


class MyController {

 VoidCallback onIncrement;


 void dispose() {

   onIncrement = null;

 }

}


MyController is a simple class with onIncrement property of type VoidCallback and dispose method. onIncrement will be assigned with _incrementCounter method of state.

If you want to pass the arguments as well then use type Function in place of VoidCallback in MyController class as follows:


Function(arg1, arg2) functionWithArgs;


MyWidget is the stateful widget which will be managed by MyController object. Controller object will be passed in constructor of MyWidget as follows: 


const MyWidget({

  @required this.controller,

}) : assert(controller != null);


We will assign method to controller property in state’s init method as follows:


void initState() {

 super.initState();

 widget.controller.onIncrement = _incrementCounter;

}


Now whenever the controller’s onIncrement will be called the state’s _incrementCounter will be called resulting in increment and rebuilding of MyWidget.


By doing so we have enabled rebuilding of only required widget and not the complete Scaffold as it was rebuilding in default example.


IMPORTANT : Don't forget to call the controller's dispose method in parent’s dispose method.


Full modified code: 



Comments