Stateless and Stateful Widgets#
[TOC]
Stateless Widget#
Definition: A widget that does not change once it is built.
Use Case: Good for static content that depends only on its configuration (constructor parameters) and the parent widget’s context.
Lifecycle: It is built once and does not rebuild unless the parent rebuilds it.
Examples:
Text
,Icon
,Container
(when used with fixed values).
Code Example:
class MyStatelessWidget extends StatelessWidget {
final String title;
MyStatelessWidget({required this.title});
@override
Widget build(BuildContext context) {
return Text(title);
}
}
Stateful Widget#
Definition: A widget that can change its appearance or behavior in response to events, user input, or data changes.
Use Case: Good for interactive widgets that update dynamically, such as forms, animations, or buttons that change when pressed.
Lifecycle: A
StatefulWidget
has two classes:The widget class (immutable).
The State class (mutable, where the logic and changing data live). Flutter rebuilds the UI when
setState()
is called inside theState
class.
Code Example:
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int counter = 0;
void _increment() {
setState(() {
counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Counter: $counter'),
ElevatedButton(
onPressed: _increment,
child: Text('Increment'),
),
],
);
}
}
Key Difference in One Sentence
A StatelessWidget is immutable (cannot change after it’s built).
A StatefulWidget is mutable (can rebuild itself when its state changes).
Here’s a clear side-by-side comparison table of Stateless vs Stateful Widgets in Flutter that you can use for teaching:
Feature |
StatelessWidget |
StatefulWidget |
---|---|---|
Mutability |
Immutable – cannot change once built |
Mutable – can change during runtime |
Rebuild Trigger |
Rebuilt only when parent widget rebuilds |
Can rebuild itself using |
Lifecycle |
Has only the |
Has both widget class and |
Data Handling |
Displays data that never changes (static content) |
Manages data that may change over time (dynamic content) |
Use Cases |
Static UI like |
Interactive UI like counters, forms, animations, checkboxes |
Performance |
Lightweight and efficient |
Slightly heavier due to state management |
Examples |
|
Counter app, toggle switches, form inputs |
Summary:
Use StatelessWidget for static UI.
Use StatefulWidget for interactive/dynamic UI.
Why a Stateful Widget needs a State
class#
A StatefulWidget
is split into two parts:
The widget class
Immutable.
Holds configuration data (like constructor parameters).
Exists only to tell Flutter: “Here is how my UI should be built.”
The
State
classMutable.
Holds the data that can change over time.
Provides the logic for updating the UI.
Calls
setState()
to tell Flutter to rebuild the widget tree.
Why not just put everything in one class?#
Flutter’s UI system is built around immutability:
All widgets in Flutter are immutable (their fields cannot change once created).
When something changes, Flutter doesn’t “mutate” the widget — it rebuilds a new widget tree.
If StatefulWidget
itself were mutable, it would break this consistency. By separating configuration (StatefulWidget
) from behavior (State
), Flutter achieves:
Performance efficiency: only the
State
object is preserved during rebuilds, not the whole widget.Clarity: you can see which parts are static (the widget class) and which parts are dynamic (the state).
Reusability: the same widget class can be paired with different states in different contexts.
How it works in practice#
When Flutter rebuilds:
The old
State
object is kept.The new
StatefulWidget
object is created (with new config data if needed).The existing
State
is reattached to this new widget.
That’s why you must inherit from State
— so Flutter knows:
where to store your mutable data, and
how to rebuild your widget when that data changes.
In short:#
A StatefulWidget
is immutable by design. Its mutable companion, the State
class, exists to hold data and logic that can change. That’s why every StatefulWidget
must be paired with a State
subclass.