Flutter's State Lifecycle: From Creation to Disposal
A Flutter State object outlives its widget configuration. The framework manages its journey from creation (`initState`) to permanent removal (`dispose`), calling methods like `build` along the way. This governs all `StatefulWidget`s.
WHY IT EXISTS Flutter's declarative UI means widgets are frequently rebuilt. To preserve information across these ephemeral rebuilds, the framework separates the configuration (the Widget) from the long-lived, mutable state (the State object). The state lifecycle provides predictable hooks for managing this persistent state.
THE MENTAL MODEL A State object is a stage actor, and the Widget is their script for a scene. The actor (State) is hired once (initState) and stays on set. They may get revised scripts (didUpdateWidget) and perform the scene many times (build). They might leave the stage briefly (deactivate) and return, but only when their contract ends (dispose) do they pack up and go home for good. The State is the persistent entity; the Widget is just its current configuration.
HOW IT WORKS The framework creates a State object via StatefulWidget.createState. The object is now mounted. The framework then calls initState for one-time setup. After that, didChangeDependencies runs. From this point, build can be called many times to render the UI. If the parent provides a new widget configuration, didUpdateWidget is called, followed by another build. If the widget is removed from the tree, deactivate is called. If it's not reinserted into the tree by the end of the animation frame, dispose is called, the object is unmounted, and it will never be used again.
WHEN TO USE IT You use these lifecycle methods in every StatefulWidget. Use initState to subscribe to streams or initialize controllers. Use didUpdateWidget to react to changes in the widget's constructor parameters. Use build to describe your UI based on the current state. Crucially, use dispose to cancel subscriptions and release resources to prevent memory leaks.
WHEN NOT TO USE IT Don't perform expensive work in the State constructor; initState is the correct place, as context is available there. Don't call setState within didUpdateWidget, as a build is already scheduled to run after it. Do not put final resource cleanup in deactivate; since the state object might be re-inserted into the tree, this can cause errors. Cleanup belongs in dispose.
ONE CANONICAL EXAMPLE Initializing an AnimationController in initState and releasing it in dispose is a classic use case. This ensures the controller exists for the entire life of the State object but is properly cleaned up when the State is permanently destroyed, preventing memory leaks.
Read the original → api.flutter.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.