StatefulWidget — widget Flutter dengan status yang dapat diubah, memungkinkan UI merespons tindakan pengguna, peristiwa asinkron, dan aliran data. Menurut dokumentasi resmi Flutter (Flutter.dev, 2026), StatefulWidget digunakan untuk semua elemen interaktif aplikasi: formulir input, animasi, kotak centang, sakelar, dan layar yang memuat data dari jaringan. Berbeda dengan StatelessWidget, ia membuat objek State terpisah yang dipertahankan sepanjang siklus hidup dan dapat dibangun ulang tanpa membuat ulang widget itu sendiri.
Poin Utama
StatefulWidget — adalah kelas Flutter yang dapat mengubah statusnya sebagai respons terhadap tindakan pengguna, peristiwa sistem, atau operasi asinkron. Berbeda dengan StatelessWidget, StatefulWidget tidak ditampilkan secara langsung — ia membuat objek State yang bertanggung jawab untuk rendering. Pembagian menjadi dua kelas (Widget dan State) memungkinkan Flutter membangun ulang UI tanpa membuat ulang widget itu sendiri, yang memberikan keuntungan kinerja signifikan pada pembaruan yang sering.
Arsitektur StatefulWidget mengikuti pola «pemisahan yang dapat diubah dan tidak dapat diubah»: widget itu sendiri tetap tidak dapat diubah (seperti StatelessWidget), dan semua status yang dapat diubah disimpan dalam objek State terpisah. Ini memungkinkan Flutter menggunakan kembali widget dengan membandingkannya berdasarkan jenis dan Key, sambil mempertahankan status terkini di antara pembangunan ulang.
Menurut Google (Flutter Architectural Overview, 2026), StatefulWidget optimal untuk skenario di mana status berubah lebih dari sekali selama masa hidup widget: bidang teks, animasi, timer, aliran data, pemuatan asinkron. Untuk inisialisasi satu kali, StatelessWidget sudah cukup.
StatefulWidget wajib digunakan ketika widget harus merespons peristiwa eksternal: penekanan tombol, penyelesaian permintaan HTTP, pembaruan data dari database, langganan WebSocket. Juga diperlukan untuk widget dengan animasi, bidang teks dengan kontroler, dan komponen yang mengelola fokus. Jika widget hanya menampilkan data dan tidak menghasilkan peristiwa — gunakan StatelessWidget.
StatefulWidget terdiri dari dua kelas: StatefulWidget itu sendiri (ringan, tidak dapat diubah) dan State (berat, dapat diubah). Framework membuat State melalui metode createState(), yang dipanggil sekali saat ditempatkan di pohon. State mendapatkan referensi ke widget melalui properti widget dan dapat mengakses bidangnya kapan saja selama siklus hidup.
Siklus hidup StatefulWidget terdiri dari enam tahap utama, yang masing-masing menyediakan metode yang dapat ditimpa untuk melakukan tugas-tugas spesifik. Memahami tahapan ini sangat penting untuk bekerja dengan benar dengan sumber daya dan menghindari kebocoran memori.
createState — metode pertama dari siklus hidup, dipanggil saat StatefulWidget ditempatkan di pohon. Harus mengembalikan instance baru State yang terkait dengan widget ini. Metode ini dipanggil tepat satu kali sepanjang masa hidup elemen. Penting untuk tidak melakukan operasi berat di sini — createState harus seringan mungkin.
initState — dipanggil segera setelah pembuatan State, sebelum pembangunan UI pertama. Di sini dilakukan: inisialisasi kontroler (TextEditingController, AnimationController), langganan aliran data (StreamSubscription), pengaturan timer, dan inisialisasi awal bidang. Menurut dokumen Flutter (Flutter.dev, 2026), di initState tidak boleh memanggil BuildContext.of() — pohon belum sepenuhnya terpasang.
didChangeDependencies — dipanggil setelah initState dan setiap kali dependensi InheritedWidget berubah. Ini adalah tempat yang tepat untuk memanggil MediaQuery.of(context) atau berlangganan Theme — nilai yang dapat berubah selama aplikasi berjalan. Jika widget menggunakan InheritedWidget, logika inisialisasi harus di sini, bukan di initState.
build — metode utama yang mengembalikan pohon widget. Dipanggil setelah initState, setelah didChangeDependencies, dan setelah setiap setState. didUpdateWidget dipanggil ketika induk membangun ulang dan mengirimkan StatefulWidget dengan parameter baru. Di sini Anda dapat membandingkan bidang widget lama dan baru dan, jika perlu, memperbarui status.
dispose — tahap akhir dari siklus hidup. Di sini semua sumber daya dibebaskan: berhenti berlangganan dari aliran, menghapus kontroler, membatalkan timer. Tidak memanggil dispose menyebabkan kebocoran memori. Setelah dispose, State dianggap mati — memanggil setState di dalamnya akan melempar pengecualian.
Mekanisme kerja StatefulWidget didasarkan pada kerja terkoordinasi dari tiga entitas: Widget (deskripsi ringan), Element (lapisan perantara), dan State (penyimpan data). Ketika Flutter menemukan StatefulWidget dalam deskripsi, ia membuat StatefulElement yang memanggil createState dan menyimpan referensi ke objek State. Saat induk membangun ulang, Flutter membandingkan widget baru dengan Element saat ini — jika jenis dan Key cocok, Element diperbarui dan State tetap sama.
Status hanya berubah melalui pemanggilan setState, yang memberi tahu framework tentang perlunya pembangunan ulang. Penting untuk dipahami: setState tidak mengubah status secara otomatis — ia hanya menandai widget sebagai «kotor». Pengembang memperbarui sendiri bidang State di callback yang diteruskan ke setState. Setelah callback selesai, Flutter memanggil build dan memperbarui UI.
Menurut tim Dart/Flutter (Dart Language Specification, 2026), pemisahan ini menjamin bahwa semua perubahan status terjadi secara sinkron sebelum pemanggilan build, menghilangkan situasi di mana UI menampilkan data yang diperbarui sebagian. Ini adalah mekanisme kunci konsistensi antarmuka di Flutter.
Mari kita lihat StatefulWidget sederhana — penghitung klik tombol. Ini menunjukkan pola dasar: pembuatan State, inisialisasi bidang di initState, perubahan melalui setState:
class CounterScreen extends StatefulWidget {
const CounterScreen({super.key});
@override
State<CounterScreen> createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Jumlah: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Tambah'),
),
],
);
}
}
Contoh dengan pemuatan data asinkron dan manajemen siklus hidup. StatefulWidget memuat data dari jaringan dan menampilkan status pemuatan:
class UserProfilePage extends StatefulWidget {
final String userId;
const UserProfilePage({super.key, required this.userId});
@override
State<UserProfilePage> createState() => _UserProfilePageState();
}
class _UserProfilePageState extends State<UserProfilePage> {
UserModel? _user;
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadUser();
}
Future<void> _loadUser() async {
final user = await UserService.fetchUser(widget.userId);
setState(() {
_user = user;
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
if (_isLoading) return const CircularProgressIndicator();
return Text('Halo, ${_user!.name}');
}
}
Dalam contoh kedua, penting untuk dicatat: initState memulai operasi asinkron, tetapi metode itu sendiri tidak asinkron. Asinkronitas direalisasikan melalui async/await di dalam metode terpisah _loadUser, yang memperbarui status melalui setState setelah permintaan selesai. Pendekatan ini menjamin bahwa widget akan menampilkan indikator pemuatan dengan benar sebelum menerima data.
Pilihan antara StatefulWidget dan StatelessWidget bukan hanya soal keberadaan status. StatefulWidget menyediakan siklus hidup lengkap dengan metode initState, didChangeDependencies, didUpdateWidget, dan dispose, yang diperlukan untuk bekerja dengan kontroler, animasi, dan aliran. StatelessWidget, pada gilirannya, tidak memiliki metode ini dan selalu lebih ringan untuk framework.
Rekomendasi tim Flutter (Flutter docs, 2026) — minimalkan jumlah StatefulWidget dalam aplikasi, dengan mengangkat status ke atas pohon (State Hoisting) atau menggunakan solusi manajemen status (Riverpod, Bloc, Provider). Setiap StatefulWidget membuat objek State yang hidup sampai elemen dihapus — semakin banyak widget seperti itu, semakin tinggi beban memori.
| Kriteria | StatefulWidget | StatelessWidget |
|---|---|---|
| Status | Dapat diubah | Tidak dapat diubah |
| Siklus hidup | 6 tahap | Hanya build |
| Objek State | Dibuat terpisah | Tidak diperlukan |
| setState | Tersedia | Tidak tersedia |
| Langganan | initState/dispose | Tidak didukung |
| Konstruktor const | Terbatas | Sepenuhnya didukung |
| Konsumsi memori | Lebih tinggi | Lebih rendah |
StatefulWidget membutuhkan lebih banyak sumber daya daripada StatelessWidget karena kebutuhan untuk membuat dan memelihara objek State. Namun, penggunaan StatefulWidget yang benar tidak menyebabkan masalah kinerja jika beberapa aturan dipatuhi. Pertama, hindari penyarangan StatefulWidget yang dalam — setiap level menambah overhead untuk traversal pohon. Kedua, bagi StatefulWidget kompleks menjadi beberapa widget sederhana, yang masing-masing bertanggung jawab atas bagian statusnya sendiri.
Menurut penelitian Flutter Performance (Flutter.dev, Februari 2026), penyebab paling umum penurunan FPS adalah pemanggilan setState di widget induk yang membangun ulang semua turunan, termasuk StatelessWidget yang tidak mengubah tampilannya. Solusinya — pindahkan bagian UI yang dapat diubah ke StatefulWidget terpisah, sehingga setState hanya membangun ulang widget minimum yang diperlukan.
Penggunaan const di dalam State adalah teknik penting lainnya. Jika widget anak dinyatakan sebagai const, Flutter tidak akan membangunnya ulang saat setState dipanggil di induk. Ini mengurangi beban framework dan memperpendek waktu rendering frame.
Setiap pemanggilan setState memicu pembangunan ulang penuh widget. Jika status berubah dengan frekuensi tinggi (misalnya, animasi atau aliran data), pertimbangkan penggunaan AnimatedBuilder, ValueListenableBuilder, atau StreamBuilder daripada pemanggilan setState manual. Widget ini mengoptimalkan pembangunan ulang, hanya memperbarui bagian UI yang benar-benar berubah.
Kesalahan umum pertama dengan StatefulWidget — memanggil setState setelah dispose. Ketika widget dihapus dari pohon, State dianggap mati dan setiap panggilan setState melempar pengecualian «setState called after dispose». Paling sering ini terjadi ketika operasi asinkron selesai setelah widget dihapus. Solusinya — periksa bendera mounted sebelum memanggil setState atau batalkan operasi asinkron di dispose.
Kesalahan kedua — melakukan perhitungan berat di metode build. Karena build dipanggil pada setiap setState dan setiap pembangunan ulang induk, semua perhitungan harus seringan mungkin. Jika perlu melakukan operasi intensif sumber daya — pindahkan ke Isolate terpisah atau simpan hasilnya di bidang State.
Kesalahan ketiga — tidak memanggil super.initState() dan super.dispose(). Saat menimpa metode ini, pengembang wajib memanggil implementasi induk. Jika tidak dilakukan, framework tidak dapat mengelola status Element dengan benar, yang mengarah ke bug yang sulit dilacak.
mounted sebelum setState di callback asinkronsuper.initState() dan super.dispose()Pertanyaan yang Sering Diajukan
StatefulWidget dapat mengubah statusnya melalui setState, memiliki siklus hidup (initState, dispose) dan membuat objek State terpisah. StatelessWidget tidak dapat mengubah status dan tidak memiliki metode siklus hidup — ia hanya menampilkan data yang diberikan.
createState dipanggil tepat satu kali untuk setiap instance StatefulElement. Bahkan jika induk membangun ulang berkali-kali, selama jenis dan Key widget tidak berubah, createState tidak dipanggil — objek State yang ada digunakan.
Sumber daya tidak akan dibebaskan: kontroler akan terus bekerja di latar belakang, langganan aliran akan tetap aktif, timer tidak akan dibatalkan. Ini menyebabkan kebocoran memori dan dapat memicu pemanggilan setState setelah dispose, yang melempar pengecualian.
Ya, konstruktor StatefulWidget bisa const. Namun, ini tidak memberikan keuntungan yang sama seperti untuk StatelessWidget — objek State akan tetap dibuat saat penempatan pertama. const hanya memengaruhi widget itu sendiri (pembungkus ringan), bukan State.
didUpdateWidget dipanggil ketika induk mengirimkan StatefulWidget dengan parameter baru. Ini diperlukan untuk menyinkronkan status dengan data baru — misalnya, jika userId berubah di parameter, profil pengguna baru perlu dimuat.
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