LifeCycle Methods of Flutter Widgets

Widgets in Flutter are associated with certain methods that demonstrate different stages of the widget from its initialization to destruction. These methods are known as the Lifecycle Methods of Flutter Widgets as they help determine the Lifecycle of the Widgets. It is however important to understand that the application lifecycle is not the same as the widget lifecycle. In this guide, we discuss the stages in the Lifecycle of Stateless and Stateful widgets.

So lets begin,

Flutter widgets are broadly classified as Stateless and Stateful Widget based on whether or not they hold state within themselves. But what is State actually?

According to Flutter, State is the information that can be read synchronously when the widget is built and might change during the lifetime of the widget. In simple terms, state refers to the values or data that a widgets holds that may on may not alter. Widgets can be differentiated as Stateless and Stateful based on this.

Stateless Widgets and their lifecycle

Stateless widgets do not carry any internal state. The build() method only runs once inside that widget when it is created. Data inside Stateless Widget are immutable i.e. they cannot be changed until and unless a new instance of the widget itself are initialized again with different configurations and properties. They are used for still structures or constant widgets in an application for example, the AppBar, or the color scheme, i.e. generally the User Interface(UI).

Stateless widgets have quite a simple lifecycle. They only have one lifecycle method i.e. the build() method. This method automatically triggers the widget rendering process. Inside the build() method is where you define and declare different components that appear in your application. For a stateless widget the build() method runs only once.

class HomePage extends StatelessWidget {
 

  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}

Stateful Widgets and their lifecycle

In contrast to Stateless widgets, Stateful widgets are dynamic and carry a mutable internal state. This means that they can be easily modified throughout their life cycle without the need of re-initialization. Stateful widgets are used when we require dynamic updates in the application’s state at run time.

For example: triggering an action in the application when a user presses a button. These widgets are hence the most frequently used widgets when creating flutter applications.

When building a Stateful Widget in Flutter, the framework generates a state object linked to its widget. The state object is responsible for holding all mutable states for the widget.

Stateful Widgets have their lifecycle based on their state and how it changes. When a Stateful Widget is built its constructor function is executed first followed by a call to the createState() method. The lifecycle starts with the createState() method.

The various stages and methods in the lifecycle of a Stateful widget can be explained as follows:

Figure: Stateful Widget LifeCycle methods

1. createState()

The createState() method is responsible for creating a State object. This method must be overridden and is mandatory within a Stateful Widget. The object holds all mutable states for a given Stateful Widget.

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}

All widgets have a boolean property named mounted. Upon creation of a State object, the framework associates it to a BuildContext by setting mounted to true. Mounted = true shows that the given State object and Stateful Widget is in the widget tree. Mounted is useful when a state method calls the setState(), however, it is unclear as to how many times the given method itself is called. Calling setState() when a widget is unmounted can throw an error. Hence, we can check for if(mounted) {… to confirm either or not the state exists before making a setState() call.

Note: mounted == true, works in the background and isn’t specified as a definite stage of a Stateful widget Lifecycle.

2. initState()

Once the state object is inserted into the widget tree initState() is executed automatically after the class constructor. This method strictly executes only once. It also requires to call the super.initState() method. super.initState() forwards to the default implementation of the State<T> base class of your widget that helps the widgets function properly.

Within initState() we can initialize variables, data, properties, etc. and subscribe to Streams, ChangeNotifiers, or any other object that could change the data on a given widget.

@override
void initState() {
super.initState();
// TODO: implement initState
}

3. didChangeDependencies()

didChangeDependencies() method is called on account to dependancy change in a state object that a given widget relies on. It is also called immediately after the initState(). Subclasses seldom use this method as the framework always triggers build() after a dependency change. This method is most used by subclasses in cases when network fetches need to take place following a dependancy change which would otherwise prove too expensive to do for every build.

BuildContext.dependOnInheritedWidgetOfExactType can be called from within this method as well. This can help the state listen to changes on a Widget it is inheriting data from.

@override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }

4. build()

The build() method is the most essential lifecycle method for both a stateless and a stateful widget. It is responsible for describing and rendering widgets and their changes onto the screen that constitute the User Interface of any application. On execution it returns a newly created constellation of widgets that are configured with information from this widget’s constructor and from the given BuildContext.

It is a required and overidden method which is triggered everytime a widget is rebuilt. This can be after a call to initState()didChangeDependencies(), didUpdateWidget() or when the state is changed via call to setState().

@override
Widget build(BuildContext context) {
   return Container(color:Colors.red);
}

5.didUpdateWidget()

As the name suggests, if a parent widget updates or changes its configurations and requires widgets rebuilds with the same runtimeType and Widget.key then didUpdateWidget() method is called. It takes the old widget as an argument that may be used to compare with the new widget. The build() method executes after this method.

When the state’s build() method depends on a Stream or other object that can change, the didUpdateWidget() helps unsubscribe from the old object and re-subscribe to the new instance.

Note: This method can act as a replacement for initState() if it is expected that the widget associated with its state object requires rebuilding.

@override
void didUpdateWidget(Home oldWidget) {
  super.didUpdateWidget(oldWidget);
    // TODO: implement didUpdateWidget
}

6. setState()

Triggering a change in the state of an object within a widget can be done inside a Stateful widget. The setState() is a special method in the Stateful widget class that helps notify the flutter framework of – dirty states i.e. changes in the state object and the need to rebuild the necessary widget. It can both be automatically invoked by the framework and called by developers. When calling the setState(), the build function is triggered for that state object which in turn updates the UI.

It is therefore important to understand that changing the state of a state object should be done within the setState() method. Changing state outside of setState() won’t trigger the build method to rebuild the UI as a result of which the change will not be reflected as needed.

setState() doesn’t take an async callback due to which it can be called whenever required.

setState(() {
// setState implementation
});

7. deactivate()

deactivate() is called when the State is removed temporarily from the tree. However, before the current frame change the state can be inserted back to a different part in the tree. This method exists so as to move state objects from one point of the tree to another. When re-inserting the state object to a different location the build() method is triggered.

Implementations of this method should end with a call to the inherited method,super.deactivate().

@override
void deactivate() {
super.deactivate();
// TODO: implement deactivate
}

8. dispose()

The dispose() method is called to permanently remove a state object from a widget tree. With this the state object’s mounted property is set to false indicating that it will never be built again.

Within the dispose() method we release resources held by the corresponding object. An instance of using this method can be while using the PushReplacement() of the Navigator to replace the current widget with a new one.

@override
void dispose() {
super.dispose();
// TODO: implement dispose
}

Upon calling the dispose() method the state object’s mounted property is set to false and it is removed from the widget tree.

The state object can then never remount.

Thats all for the lifecycle methods and essential properties of stateful and stateless widgets. Hope this article was helpful.

Happy reading!

Tags:

Samriddhi is a curious and problem solving software developer. A go-getter and a passionate team player who loves converting the designs to high class functional codes.