Explain the widget lifecycle in Flutter.
Short Answer
A StatefulWidget's State goes through createState → initState → didChangeDependencies → build (repeated) → didUpdateWidget (on parent rebuild) → deactivate → dispose.
createState() is called once when the framework first creates the State object. initState() runs once, right after, and is where you set up controllers, subscriptions, or one-time initialization — note that BuildContext and inherited widgets aren't fully available yet, so don't use them here for anything that depends on InheritedWidget data.
didChangeDependencies() runs after initState() and again whenever an InheritedWidget the State depends on changes. build() is called every time the framework needs to re-render — it can run many times and must be fast and side-effect-free. If the parent rebuilds with a new widget instance for the same State, didUpdateWidget(oldWidget) runs so you can react to changed configuration. Finally, deactivate() runs when the State is removed from the tree (it may be reinserted elsewhere, e.g. with GlobalKey), and dispose() runs when it's permanently removed — this is where you cancel subscriptions and dispose controllers.
Common Mistakes
- ×Doing expensive work inside build() instead of initState() or a memoized value.
- ×Forgetting to dispose() AnimationControllers, StreamSubscriptions, or TextEditingControllers, causing memory leaks.
Interview Tips
- →Naming the exact order (initState → didChangeDependencies → build → didUpdateWidget → dispose) signals real hands-on experience, not just memorized definitions.
Related Questions
What is the difference between StatelessWidget and StatefulWidget?
A StatelessWidget is immutable and rebuilds only when its parent rebuilds; a StatefulWidget holds mutable state via a separate State object and can rebuild itself whenever that state changes.
How does Flutter manage memory, and how do you avoid leaks?
Dart uses automatic garbage collection, so you don't free memory manually — leaks in Flutter almost always come from long-lived objects (controllers, streams, listeners) holding references that prevent disposed widgets' resources from being collected.