Deep Dive: Flutter’s (Stateful) Widget Lifecycle

Vishnureji
4 min readJul 24, 2023

--

Flutter, Google’s open-source UI software development kit, has gained immense popularity among developers for building beautiful and high-performance mobile applications. One of the key components of Flutter’s architecture is its widgets, which are the building blocks of the user interface. In this blog, we’ll take a deep dive into the lifecycle of a Flutter (Stateful) widget and understand how it works with an example code.

Understanding Flutter’s Widget Lifecycle

In Flutter, widgets can be classified into two main types: Stateless and Stateful. Stateless widgets are immutable and don’t change their state during the lifetime of the widget. On the other hand, Stateful widgets are mutable and can change their state multiple times during their lifetime. Let’s focus on the lifecycle of a Stateful widget, as it involves more complex interactions compared to the Stateless widget.

The lifecycle of a Stateful widget consists of several phases, and Flutter provides hooks to perform actions at each stage. Understanding these phases is crucial for managing and controlling the state of your widget efficiently.

Here are the main lifecycle phases of a Stateful widget:

  1. createState(): This is the first method called when the widget is created. It returns the associated State object, which will be used to maintain the state of the widget throughout its lifecycle.
  2. initState(): This method is called right after createState(). It is used to initialize the state of the widget or any other one-time setup. This method is called only once during the widget’s lifecycle.
  3. didChangeDependencies(): If the dependencies of the widget change after initState(), this method is called. It provides an opportunity to react to changes in the widget’s dependencies. It may be called multiple times during the widget’s lifecycle.
  4. build(): This is a mandatory method and is called after initState() and didChangeDependencies(). It is responsible for constructing the widget’s UI and returns a widget tree.
  5. didUpdateWidget(): If the parent widget rebuilds and updates the current widget, this method is called. It provides an opportunity to respond to changes in the widget’s configuration.
  6. setState(): This method is crucial for managing the state of the widget. When you call setState(), it triggers a rebuild of the widget, and Flutter takes care of updating the UI with the new state.
  7. deactivate(): If the widget is removed from the widget tree, this method is called. It allows you to perform any cleanup or pause ongoing animations.
  8. dispose(): This is the final method in the lifecycle. It is called when the widget is removed permanently from the widget tree. It is essential to release any resources held by the widget in this method.

Example Code

Let’s go through an example to see the Stateful widget lifecycle in action. We’ll create a simple counter app that increments a number on button press.

import 'package:flutter/material.dart';
class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int _counter = 0;
@override
void initState() {
super.initState();
print("initState() called.");
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("didChangeDependencies() called.");
}
@override
void didUpdateWidget(CounterApp oldWidget) {
super.didUpdateWidget(oldWidget);
print("didUpdateWidget() called.");
}
@override
Widget build(BuildContext context) {
print("build() called.");
return Scaffold(
appBar: AppBar(title: Text("Counter App")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Count:", style: TextStyle(fontSize: 24)),
Text("$_counter", style: TextStyle(fontSize: 36)),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: Icon(Icons.add),
),
);
}
@override
void deactivate() {
super.deactivate();
print("deactivate() called.");
}
@override
void dispose() {
super.dispose();
print("dispose() called.");
}
}
void main() => runApp(MaterialApp(home: CounterApp()));

In this example, the _CounterAppState class is our Stateful widget. The initState(), didChangeDependencies(), build(), didUpdateWidget(), deactivate(), and dispose() methods are overridden to demonstrate the different lifecycle phases. We also have a _counter variable that gets updated when the FloatingActionButton is pressed.

When you run the app, observe the debug console to see the order in which these methods are called. You’ll notice that initState() and didChangeDependencies() are called only once, while build() and didUpdateWidget() are called every time the state changes.

Conclusion

Understanding the lifecycle of a Stateful widget is crucial for managing the state and ensuring your app’s smooth operation. By utilizing the different lifecycle methods efficiently, you can handle updates and perform necessary cleanup operations. Flutter’s widget lifecycle provides developers with a powerful toolset to create robust and dynamic mobile applications.

Remember to utilize the setState() method whenever you need to update the state of a widget. This triggers a rebuild of the widget, and Flutter will take care of updating the UI accordingly.

I hope this blog has shed light on Flutter’s (Stateful) widget lifecycle and its importance in building Flutter apps. Happy coding! 😊

References:

--

--

Vishnureji
0 Followers

Frontend Developer | Flutter | HTML | css | JavaScript