Flutter setState explained for beginners
November 3, 2026 · 2 min read
To make a Flutter screen change when someone taps, use a StatefulWidget and wrap the change in setState(() { ... }). setState runs your change, then tells Flutter to call build again so the screen shows the new value.
A counter that updates on tap
This is a complete app. Save it as lib/main.dart and run it with flutter run:
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: CounterScreen()));
class CounterScreen extends StatefulWidget {
const CounterScreen({super.key});
@override
State<CounterScreen> createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Text('Taps: $_count', style: const TextStyle(fontSize: 28)),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
child: const Icon(Icons.add),
),
);
}
}
The screen starts with Taps: 0. Each tap on the button changes the text to Taps: 1, Taps: 2, and so on.
What's happening
A StatelessWidget can't do this. Its fields are final, and Flutter only rebuilds it when the widget above it rebuilds.
A StatefulWidget has two parts:
CounterScreenis the widget. It stays simple and holds no changing values._CounterScreenStateis the State object. Flutter keeps it alive while the screen is showing, and it holds_countand thebuildmethod.
When you tap the button, setState increases _count and then Flutter calls build again. The new Text shows the new number.
To turn a stateless counter into this one, change extends StatelessWidget to extends StatefulWidget, add createState, and move build and your changing variables into the State class.
Common mistake
Changing the value without setState:
onPressed: () => _count++, // _count changes, the screen doesn't
The variable goes up, but Flutter never rebuilds, so the text stays at Taps: 0. Fix it by wrapping the change:
onPressed: () => setState(() => _count++),
Takeaway
Keep values that change in a State object, and change them inside setState. No setState, no redraw.