Setiap widget pada Flutter tergolong stateless atau stateful, dan pembeda ini menstrukturkan hampir seluruh kode Flutter. Kuncinya terletak pada state, yaitu data yang dapat berubah selama sebuah widget tetap tampil, misalnya status centang pada kotak centang atau teks yang sedang diketik. Topik ini mendefinisikan kedua kategori, menampilkan anatomi kelasnya, menyajikan tabel perbandingan, dan menutup dengan panduan memilih kategori yang tepat saat sebuah widget baru dirancang.
Widget stateless: tampilan dari konfigurasi#
StatelessWidget adalah widget tanpa state internal, sehingga tampilannya sepenuhnya ditentukan oleh nilai yang diterimanya melalui constructor. Data itu bersifat final dan tidak pernah diubah oleh widget itu sendiri. Apabila tampilan harus berubah, widget baru dengan nilai yang berbeda dibuat dari luar widget tersebut.
// tidak-dijalankan
class LabelStatus extends StatelessWidget {
const LabelStatus({super.key, required this.selesai});
final bool selesai;
@override
Widget build(BuildContext context) {
return Text(selesai ? 'Tugas selesai' : 'Tugas belum selesai');
}
}LabelStatus menerima satu nilai selesai lalu menampilkan teks yang sesuai. Satu-satunya cara mengubah tampilannya adalah membuat LabelStatus baru dengan nilai yang berbeda, dan pembuatan itu menjadi tugas widget induk. Aliran data bergerak satu arah, yaitu turun dari induk ke anak, dan widget tidak pernah mengubah apa pun di atasnya.
Widget stateful: state yang bertahan antar-rebuild#
StatefulWidget adalah widget yang menyimpan state pada objek State terpisah, dan objek itu bertahan antar-rebuild sehingga nilai yang sudah berubah tidak hilang saat tampilan digambar ulang. Inilah perbedaannya dengan widget stateless yang seluruh masa hidupnya bergantung pada konfigurasinya.
Anatomi StatefulWidget terdiri atas dua kelas. Kelas pertama adalah widgetnya sendiri, yang tetap immutable dan hanya memuat konfigurasi yang tidak berubah. Kelas kedua adalah kelas State yang menyimpan data yang dapat berubah beserta metode build. Keduanya dihubungkan oleh metode createState, yang dipanggil framework sekali saat widget pertama kali masuk ke pohon.
// tidak-dijalankan
class PenghitungTugas extends StatefulWidget {
const PenghitungTugas({super.key});
@override
State<PenghitungTugas> createState() => _PenghitungTugasState();
}
class _PenghitungTugasState extends State<PenghitungTugas> {
int _jumlahSelesai = 0;
void _tandaiSelesai() {
setState(() {
_jumlahSelesai++;
});
}
@override
Widget build(BuildContext context) {
return Text('$_jumlahSelesai dari 5 tugas selesai');
}
}_jumlahSelesai tersimpan pada kelas State, bukan pada widget. Saat _tandaiSelesai dipanggil, setState memberi tahu framework bahwa build perlu dipanggil ulang, kemudian Text yang baru menampilkan angka terbaru. Widget PenghitungTugas boleh dibuat ulang sebanyak apa pun, sedangkan nilai hitungannya tetap terjaga karena tersimpan pada objek State yang sama. Penamaan dengan garis bawah di awal menandai anggota yang privat terhadap satu berkas Dart. Aturan lengkap penggunaan setState dibahas pada modul Interaktivitas dan state, sedangkan perannya di sini cukup dipahami sebagai pemicu rebuild.
Objek State juga memiliki daur hidup yang sederhana pada tingkat ini. Metode initState dipanggil sekali sebelum build pertama sebagai tempat menyiapkan data, sedangkan dispose dipanggil saat widget dilepas dari pohon untuk membersihkan sumber daya yang digunakan widget. Keduanya jarang diperlukan pada widget sederhana, tetapi namanya akan sering muncul pada kode nyata.
Memilih kategori yang tepat#
Kriteria penentuannya berupa keberadaan data yang berubah selama widget tampil dan perubahannya memengaruhi tampilan. Data semacam itu menuntut StatefulWidget, sedangkan widget yang tampilannya murni fungsi dari konfigurasinya cukup menjadi StatelessWidget. Widget yang tampaknya membutuhkan state tetapi sebenarnya tidak, misalnya label yang isinya ditentukan penuh oleh widget induknya, sebaiknya tetap berupa widget stateless.
Widget stateless tetap dapat berperan dalam interaksi, yaitu melalui fungsi yang diterimanya dari widget induk. Tombol dengan properti onPressed, misalnya, dapat saja berupa widget stateless karena yang merespons peristiwa adalah fungsi milik induknya. Keberadaan callback bukan tanda bahwa pemiliknya harus stateful.
- Umumnya
StatelessWidget:TextdanIcondengan isi tetap, kartu profil, baris judul, dan widget dekoratif - Umumnya
StatefulWidget: kotak centang, field teks, saklar pengaturan, stopwatch, dan halaman dengan tab aktif
Tabel berikut merangkum perbedaan keduanya pada aspek yang paling sering ditanyakan.
| Aspek | StatelessWidget | StatefulWidget |
|---|---|---|
| State internal | Tidak ada | Ada, disimpan pada objek State |
| Jumlah kelas yang ditulis | Satu | Dua, yaitu widget dan kelas State |
| Masa hidup | Dibuat ulang pada setiap rebuild | Widget dibuat ulang, sedangkan State bertahan |
| Cara tampilan berubah | Konfigurasi baru dari widget induk | Perubahan state yang diikuti setState |
| Contoh | Label status, kartu profil, ikon | Kotak centang, field teks, stopwatch |
Baris terakhir tabel menegaskan pola yang sering muncul: widget tampilan cenderung stateless, sedangkan widget yang menampung interaksi cenderung stateful. Pembeda yang paling menentukan adalah masa hidup state, karena nilai hasil interaksi pengguna tersimpan pada state dan terjaga dari satu rebuild ke rebuild berikutnya.
Kesalahan umum#
- Menjadikan semua widget stateful karena terasa lebih aman. Kebiasaan ini menyebarkan data yang seharusnya terpusat, memperbesar cakupan rebuild, dan menyulitkan pelacakan perubahan. Perbaikannya, simpan state seminimal mungkin dan letakkan pada widget terendah yang membutuhkannya.
- Menyimpan data yang berubah pada field widget. Field pada widget wajib
finalkarena widget bersifat immutable, sehingga nilai baru tidak pernah tercermin pada tampilan. Perbaikannya, pindahkan data tersebut ke kelasStatedan ubah nilainya melaluisetState.
Ringkasan#
StatelessWidgettidak menyimpan state dan tampilannya murni fungsi dari konfigurasi yang diterima.StatefulWidgetmenyimpan state pada objekStateyang bertahan antar-rebuild, sedangkan widgetnya sendiri tetap immutable.createStatemenghubungkan widget dengan objekState-nya dan dipanggil sekali saat widget pertama masuk pohon.- Kategori dipilih dengan melihat ada tidaknya data yang berubah selama widget tampil dan memengaruhi tampilan.
Referensi#
- StatelessWidget class — Flutter API
— Dokumentasi resmi kelas
StatelessWidgetbeserta contoh penggunaannya. - StatefulWidget class — Flutter API
— Dokumentasi resmi
StatefulWidget, termasuk anatomi dua kelasnya. - State class — Flutter API
— Dokumentasi objek
State, daur hidupnya, dan metodesetState.