setState in depth
- Flutter course
- Intermediate
- Lesson 1/99
- 4 min
Learn how setState works and when it rebuilds.
setState in depth
setState marks a State object as 'dirty' and tells the framework that this widget needs to be rebuilt. The rebuild does not happen immediately; the framework defers this work until the next frame.
void increment() {
setState(() {
count++;
});
}This way multiple setState calls in a row can be merged into a single rebuild.
scheduleBuild and dirty
Internally setState does two things: first it runs the callback you gave it (e.g. count++), then it sets the _dirty flag on the State object to true and calls markNeedsBuild. That call adds the element to the scheduler's list.
setState(() { count++; });
// _dirty = true
// markNeedsBuild() scheduledWhen the next frame begins, that element's build method is called again.
Practice StatefulWidget that increments a counter
Build a StatefulWidget. The _sayac variable starts at 0. In initState, call print('başlangıç: $_sayac'). When the button is pressed, increment _sayac with setState.
Starter code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyCounter(),
);
}
}
class MyCounter extends StatefulWidget {
@override
_MyCounterState createState() => _MyCounterState();
}
class _MyCounterState extends State<MyCounter> {
int _sayac = 0;
@override
void initState() {
super.initState();
print('başlangıç: $_sayac');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sayaç')),
body: Center(
child: Text('$_sayac'),
),
floatingActionButton: FloatingActionButton(
// setState ile _sayac'ı artır
onPressed: () {},
child: Icon(Icons.add),
),
);
}
}Sample solution
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyCounter(),
);
}
}
class MyCounter extends StatefulWidget {
@override
_MyCounterState createState() => _MyCounterState();
}
class _MyCounterState extends State<MyCounter> {
int _sayac = 0;
@override
void initState() {
super.initState();
print('başlangıç: $_sayac');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sayaç')),
body: Center(
child: Text('$_sayac'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_sayac++;
});
},
child: Icon(Icons.add),
),
);
}
}Expected output
başlangıç: 0
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What happens when setState is called?
- the State is marked dirty and a rebuild is scheduled for the next frame Correct answer
- the app restarts and main runs again
- It is only valid inside initState, otherwise it throws
- the build method runs immediately in the same call stack
Explanation: setState marks the State dirty and schedules a rebuild on the next frame via markNeedsBuild; build is not called synchronously right away.
2 Complete the setState call
void artir() {
____(() {
sayac++;
});
}
void artir() {
setState(() {
sayac++;
});
}
Explanation: setState runs the given callback, then marks the State dirty and schedules a build.
3 State lifecycle parts
| Term | Meaning |
|---|---|
setState |
Marks State dirty and schedules build |
initState |
Called once when State is created |
build |
The method that returns the widget tree |
dispose |
Called when State is destroyed |