Widget Life Cycles In Flutter

Widget Life Cycles In Flutter

In flutter, a widget is either stateful or stateless. Widgets that change appearance are stateful. for example, it can change its appearance in response to events triggered by user interactions or when it receives data. Checkbox, Radio, Slider, InkWell, Form, and TextField are examples of stateful widgets. Stateful widgets subclass StatefulWidget.

A stateless widget never changes. Icon, IconButton, and Text are examples of stateless widgets. Stateless widgets subclass StatelessWidget.

A widget’s state is stored in a State object, separating the widget’s state from its appearance. The state consists of values that can change, like a slider’s current value or whether a checkbox is checked. When the widget’s state changes, the state object calls setState(), telling the framework to redraw the widget.

So basically when you need to update what is being displayed on the screen in response to user action / interaction or a change in configuration then you would need a stateful widget as it is able to update and redraw using the setState method.

Stateless widget

A stateless widget is implemented by extending StatelessWidget.

class Example extends StatelessWidget {}

The life cycle of a stateless widget consits of just the constructor and the build method

class Example extends StatelessWidget {
  Example() {
    print('This gets executed first');
  }
  @override
  Widget build(BuildContext context) {
    print('This gets executed second');
    return Container();
  }
}

Stateful widget

A stateful widget is implemented by extending StatefulWidget and creating a state object of the class by extending the State class. The State class contains the widget’s mutable state and the widget’s build() method.

class Example extends StatefulWidget {
  Example() {
    print('This gets executed first');
  }
  @override
  _ExampleState createState() {
    print('This gets executed second');
    return _ExampleState();
  }
}

class _ExampleState extends State<Example> {
  @override
  Widget build(BuildContext context) {
    print('This gets executed third');
    return Container();
  }
}

State objects are created by the framework by calling the StatefulWidget.createState method when inflating a StatefulWidget to insert it into the tree. When the widget’s state changes, the state object calls setState(), telling the framework to redraw the widget.

State objects have the following lifecycle:

  • CreateState: The framework creates a State object by overriding createState which returns an instance of the widget's state class.
@override
  _ExampleState createState() => _ExampleState();
  • InitState: After createState, initState is called. This is when the widget / object is inserted into the widget tree. The method is called exactly once for each State object it creates. Override this method to perform initialization that is required by the widget for configuration. If a State's build method depends on an object that can itself change state, for example a ChangeNotifier or Stream, or some other object to which one can subscribe to receive notifications, then be sure to subscribe properly in initState. InitState is also used for setting up things like animation controllers and state variables. If you override this, make sure your method starts with a call to super.initState().
@override
  void initState() {
    super.initState();
    // code goes here
  }
  • DidChangeDependencies: This is called immediately after initState and every other time a dependency of this State object changes. For example, if the previous call to build referenced an InheritedWidget that later changed, the framework would call this method to notify this object about the change. This method is also called immediately after initState. It is safe to call BuildContext.dependOnInheritedWidgetOfExactType from this method.
@override
  void didChangeDependencies() {
    super.didChangeDependencies();
  }
  • Build: At this point, the State object is fully initialized and the framework might call its build method any number of times to obtain a description of the user interface for this subtree. State objects can spontaneously request to rebuild their subtree by callings their setState method, which indicates that some of their internal state has changed in a way that might impact the user interface in this subtree.
@override
  Widget build(BuildContext context) {
    return Container();
  }
  • DidUpdateWidget: Called whenever the widget configuration changes. If the parent widget rebuilds and request that this location in the tree update also to display a new widget, the framework will update the widget property of the State object to refer to the new widget and then call this method with the previous widget as an argument. Override this method to respond when the widget property changes. Build is always called after this method executes, which means any calls to setState in didUpdateWidget are redundant. If you override this, make sure your method starts with a call to super.didUpdateWidget(oldWidget).
@override
  void didUpdateWidget(covariant Example oldWidget) {
    super.didUpdateWidget(oldWidget);
    // code goes here
  }
  • Deactivate: Called when this object is removed from the tree but hasn't been destroyed. The framework calls this method whenever it removes this State object from the tree (e.g., because the parent built a widget with a different runtimeType or Widget.key), the framework calls the deactivate method. If you override this, make sure to end your method with a call to super.deactivate().
@override
  void deactivate() {
    // code goes here
    super.deactivate();
  }
  • Dispose: Called when the State object is removed from the tree permanently. The framework calls this method when the State object will never build again. After the framework calls dispose, the State object is considered unmounted and the mounted property is false. Calling setState at this point would result in an error. Widgets should override this method to release any resources retained by this object (e.g., stop and dispose any active animations). If you override this, make sure to end your method with a call to super.dispose().
@override
  void dispose() {
    // code goes here
    super.dispose();
  }

Thanks for reading

Visit the flutter docs for more information on State.

You can also checkout this video tutorial which explains the different life cycle methods.