State — objek pusat manajemen data di Flutter, yang terkait dengan StatefulWidget dan bertanggung jawab untuk menyimpan informasi yang dapat diubah dan membangun antarmuka. Menurut dokumentasi resmi Flutter (Flutter.dev, 2026), State ada sepanjang siklus hidup widget dan bertahan dari pembangunan ulangnya, memastikan konsistensi data antara pembaruan UI. Tidak seperti widget itu sendiri, State dapat mengubah bidangnya dan memulai pembangunan ulang melalui panggilan setState.
Poin Penting
State — adalah objek dalam arsitektur Flutter yang menyimpan data yang dapat diubah dari StatefulWidget dan menentukan bagaimana data tersebut ditampilkan di antarmuka. Setiap StatefulWidget saat ditanamkan ke pohon membuat tepat satu objek State melalui metode createState. State ada secara independen dari widget: jika induk membangun ulang StatefulWidget dengan parameter baru, State tetap sama dan menerima widget yang diperbarui melalui properti widget.
Menurut Flutter Architectural Overview (Google, 2026), pemisahan Widget dan State adalah keputusan arsitektural yang disengaja yang memungkinkan framework menggunakan kembali elemen pohon. Widget (deskripsi ringan) dapat dibuat dan dihancurkan berkali-kali, tetapi State (objek berat dengan data) tetap di memori selama elemen berada di pohon. Ini mencegah kehilangan data saat sering terjadi pembangunan ulang widget induk.
State mengimplementasikan antarmuka StatefulWidget melalui generik: class _MyState extends State<MyWidget>. Generik mengikat State dengan tipe StatefulWidget tertentu, menyediakan akses aman-tipe ke bidangnya melalui properti widget.
Objek State disimpan di StatefulElement — lapisan perantara antara Widget dan RenderObject. StatefulElement membuat State melalui createState, menyimpan referensi ke sana dan memberikan State sebagai pemilik. Elemen dihancurkan hanya ketika widget dihapus dari pohon — hingga saat itu State hidup di memori.
Siklus hidup State bersifat deterministik dan terdiri dari urutan panggilan yang ketat. Memahami urutan ini adalah dasar untuk bekerja dengan benar dengan sumber daya dan mencegah kebocoran memori.
initState dipanggil pertama saat pembuatan State. Dalam metode ini, pengontrol, langganan aliran data, timer dan nilai awal bidang diinisialisasi. Memanggil super.initState() di baris pertama wajib dilakukan. Pada tahap initState, pohon widget belum sepenuhnya terpasang, sehingga metode seperti MediaQuery.of(context) mungkin tidak berfungsi dengan benar.
didChangeDependencies dipanggil setelah initState dan setiap kali ketergantungan InheritedWidget berubah. Di sinilah, bukan di initState, MediaQuery.of(context) atau Theme.of(context) harus dipanggil, karena pada saat ini pohon sudah terpasang. Metode ini juga dipanggil jika widget dipindahkan ke konteks lain di mana InheritedWidget memberikan nilai yang berbeda.
build — metode utama State yang mengembalikan pohon widget. Dipanggil setelah initState, setelah didChangeDependencies dan setelah setiap setState. Metode build tidak boleh memiliki efek samping — ia hanya mendeskripsikan antarmuka berdasarkan nilai bidang State saat ini.
didUpdateWidget dipanggil ketika induk membangun ulang StatefulWidget dengan parameter baru. State mendapatkan akses ke widget lama melalui oldWidget dan dapat membandingkannya dengan yang baru. Jika parameter berubah, status dapat diperbarui, data baru dimuat, atau animasi dapat dimulai ulang.
dispose — metode akhir di mana semua sumber daya dibebaskan: pengontrol, langganan, timer. Setelah dispose, State ditandai sebagai mati: mounted mengembalikan false, panggilan setState memicu pengecualian. Memanggil super.dispose() di baris terakhir metode wajib dilakukan.
| Metode | Kapan dipanggil | super wajib |
|---|---|---|
| initState | Saat pembuatan State | Ya, di baris pertama |
| didChangeDependencies | Setelah initState dan saat InheritedWidget berubah | Ya |
| build | Setelah initState, didChangeDependencies, setState | Tidak |
| didUpdateWidget | Saat widget baru dari induk | Ya |
| setState | Saat dipanggil oleh pengembang | Tidak |
| dispose | Saat dihapus dari pohon | Ya, di baris terakhir |
Mekanisme kerja State didasarkan pada tiga prinsip utama: asosiasi dengan Element, reaktivitas melalui setState dan akses ke induk melalui properti widget. Ketika Flutter membangun pohon elemen dan menemukan StatefulElement, ia memanggil createState dari widget terkait. State yang dibuat disimpan dalam elemen dan ada sampai elemen tersebut dihapus.
Saat memanggil setState, State menandai dirinya sebagai “kotor” (dirty) dan menjadwalkan pembangunan ulang untuk bingkai berikutnya. Penting: setState tidak memanggil build segera — ia hanya mencatat perlunya pembangunan ulang. Flutter mengumpulkan semua elemen kotor dalam bingkai saat ini dan membangunnya ulang secara batch, yang mengoptimalkan kinerja. Setelah panggilan build, State kembali ke status “bersih” (clean).
Properti widget memungkinkan State membaca parameter yang diteruskan ke konstruktor StatefulWidget. Karena StatefulWidget tidak dapat diubah (seperti StatelessWidget), bidangnya tidak berubah — saat parameter berubah, induk membuat widget baru, dan State menerimanya melalui didUpdateWidget. Ini menjamin bahwa State selalu bekerja dengan data induk yang terkini.
Contoh dasar State dengan bidang yang diubah oleh timer. Mendemonstrasikan initState, setState dan dispose:
class _TimerWidgetState extends State<TimerWidget> {
int _seconds = 0;
Timer? _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(
const Duration(seconds: 1),
(_) => setState(() => _seconds++),
);
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('$_seconds detik telah berlalu');
}
}
Contoh penggunaan properti widget untuk akses ke parameter induk dan reaksi terhadap perubahannya melalui didUpdateWidget:
class _GreetingState extends State<GreetingWidget> {
String _displayName = '';
@override
void initState() {
super.initState();
_displayName = _formatName(widget.name);
}
@override
void didUpdateWidget(GreetingWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.name != oldWidget.name) {
setState(() {
_displayName = _formatName(widget.name);
});
}
}
String _formatName(String name) => name.trim().isEmpty ? 'Guest' : name;
@override
Widget build(BuildContext context) {
return Text('Halo, $_displayName!');
}
}
Dalam contoh kedua, State melacak perubahan parameter masukan name dan memformat ulang tampilan hanya saat terjadi perubahan nyata. Tanpa pemeriksaan widget.name != oldWidget.name, metode akan dipanggil pada setiap pembangunan ulang induk, bahkan jika nama tidak berubah — ini pekerjaan yang tidak perlu bagi framework.
State dan StatefulWidget adalah dua kelas berbeda dalam arsitektur Flutter dengan peran yang berbeda. StatefulWidget — adalah pembungkus ringan yang tidak dapat diubah yang mendeskripsikan konfigurasi widget dan membuat State. State — adalah objek berat yang menyimpan data yang dapat diubah, mengelola langganan dan membangun UI. Pemisahan ini memungkinkan Flutter menghancurkan dan membuat widget tanpa kehilangan status.
Semua bidang StatefulWidget harus final dan diatur di konstruktor — mereka tidak berubah setelah pembuatan. State, sebaliknya, dapat mengubah bidangnya kapan saja, tetapi semua perubahan harus didahului dengan panggilan setState, agar Flutter mengetahui perlunya pembangunan ulang. Ini adalah perbedaan utama: StatefulWidget adalah “apa yang ditampilkan”, State — “bagaimana menampilkan dan data apa yang digunakan”.
Menurut Flutter source code analysis (Flutter SDK, 2026), StatefulWidget hanya berisi satu bidang wajib — createState, sementara State memiliki akses ke BuildContext, dapat berlangganan aliran, mengelola animasi dan pengontrol. Disarankan untuk menjaga StatefulWidget sesederhana mungkin, memindahkan semua logika ke State.
Pemisahan Widget dan State — keputusan arsitektural yang menjamin kekekalan konfigurasi. Jika StatefulWidget sendiri menyimpan status, pada setiap pembangunan ulang induk status akan hilang. Dengan memisahkan status ke objek terpisah, Flutter menjamin bahwa data bertahan dari pembangunan ulang, dan widget tetap ringan dan dapat dibandingkan.
Objek State terisolasi — ia tidak memiliki akses langsung ke State widget lain. Untuk pertukaran data antar widget digunakan InheritedWidget atau alat manajemen status eksternal: Provider, Riverpod, Bloc, Redux. Setiap pendekatan memecahkan masalah dengan caranya sendiri: InheritedWidget bekerja melalui pohon widget, Provider — melalui kontainer DI, Bloc — melalui aliran peristiwa.
Pilihan alat tergantung pada skala proyek. Untuk aplikasi kecil, InheritedWidget dan State lokal sudah cukup. Untuk proyek menengah dan besar, direkomendasikan Riverpod atau Bloc — mereka memberikan kemampuan pengujian, prediktabilitas dan pemisahan logika dari UI. State dalam hal ini hanya digunakan untuk data lokal widget (fokus, gulir, animasi).
Menurut Flutter Community Survey 2025 (Flutter Foundation, Desember 2025), Riverpod adalah solusi paling populer untuk manajemen status di proyek baru (38%), diikuti oleh Bloc (31%) dan Provider (22%). Ketiga alat kompatibel dengan State dan tidak memerlukan pengabaian siklus hidup standar.
Kesalahan pertama — lupa memeriksa mounted sebelum setState di callback asinkron. Ketika widget telah dihapus dari pohon (misalnya, pengguna meninggalkan layar), tetapi operasi asinkron (permintaan HTTP) masih berjalan, setelah selesai State sudah mati. Memanggil setState di State yang mati memicu pengecualian. Pemeriksaan if (mounted) setState(...) memecahkan masalah.
Kesalahan kedua — inisialisasi ketergantungan InheritedWidget di initState alih-alih didChangeDependencies. Di initState konteks belum terpasang, sehingga MediaQuery.of(context) akan memicu pengecualian. Semua ketergantungan InheritedWidget harus dikonfigurasi di didChangeDependencies atau di build.
Kesalahan ketiga — mutasi bidang tanpa memanggil setState. Jika pengembang mengubah bidang State tanpa setState, Flutter tidak akan tahu tentang perubahan dan UI tidak akan diperbarui. Contoh: _list.add(item) tanpa setState((){}) berikutnya akan mengubah daftar, tetapi layar akan tetap sama.
Pola keamanan untuk operasi asinkron di State:
Future<void> _fetchData() async {
final data = await ApiService.fetch();
if (mounted) {
setState(() => _data = data);
}
}
Pemeriksaan mounted menjamin bahwa setState hanya dipanggil untuk State yang hidup, mencegah pengecualian “setState called after dispose”.
Pertanyaan yang Sering Diajukan
StatefulWidget — konfigurasi widget yang tidak dapat diubah, sedangkan State — objek yang dapat diubah yang menyimpan data dan mengelola siklus hidup. Widget dapat dibuat ulang, State — tidak. StatefulWidget membuat State melalui createState.
Tepat satu. Metode createState dipanggil sekali saat pertama kali StatefulWidget ditanamkan ke pohon. Bahkan jika induk membangun ulang berkali-kali, objek State tetap sama, sampai tipe atau Key widget berubah.
mounted — bendera boolean yang menunjukkan apakah State berada di pohon widget. Setelah memanggil dispose, mounted menjadi false. Digunakan untuk pemeriksaan sebelum setState di callback asinkron untuk menghindari pengecualian.
Tidak. State selalu terikat ke StatefulWidget tertentu melalui generik: State<T extends StatefulWidget>. Membuat State secara langsung, tanpa asosiasi dengan widget, secara arsitektural tidak mungkin.
Akan memicu pengecualian: “setState called after dispose”. Setelah memanggil dispose, State dianggap mati dan setiap upaya untuk membangun ulang UI melalui setState dilarang. Solusi — periksa mounted sebelum setiap setState.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga