StatefulWidget & setState
A StatefulWidget can redraw itself when its data changes —
a counter that goes up on tap, for example.
Example: a tappable counter
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State createState() => _CounterState();
}
class _CounterState extends State {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: () => setState(() => count++),
child: const Text('Add'),
),
],
);
}
}
Renders "Count: 0" with an "Add" button beneath it; each tap increments the displayed count by 1.
It's split into two classes: the widget itself (Counter),
and a matching State class (_CounterState)
holding the mutable data. Calling setState() is the crucial
step — it tells Flutter "something changed, please rebuild this widget."
Changing count directly without wrapping it in
setState() would update the variable but never actually
redraw the screen, the exact same trap React's useState
lesson warns about with a plain variable instead of the state setter.
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: () => setState(() => count++),
child: const Text('Add'),
),
],
);
}
}
Renders "Count: 0" with an "Add" button beneath it; each tap increments the displayed count by 1.