← Flutter tutorial

Flutter

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.

Example
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'),
        ),
      ],
    );
  }
}
Output
Renders "Count: 0" with an "Add" button beneath it; each tap increments the displayed count by 1.