Package Provider bukan satu-satunya pilihan pengelolaan state di Flutter, dan ekosistemnya memuat beberapa keluarga pendekatan dengan bentuk yang berbeda. Topik ini memetakan posisi tiga package yang paling sering ditemui, yaitu Riverpod, Bloc, dan Redux, beserta trade-off yang menyertai masing-masing, kemudian menegaskan kapan package Provider yang sudah dipelajari memang memadai. Tujuannya bukan menetapkan pemenang, melainkan memberi bekal untuk menimbang setiap pilihan agar keputusan bagi satu aplikasi dapat diambil dengan alasan yang jelas.
Riverpod#
Riverpod menyusun ulang gagasan package Provider dengan menghapus ketergantungan pada pohon widget. Penyedianya dideklarasikan sebagai variabel global yang berdiri sendiri, widget mengaksesnya melalui objek ref alih-alih BuildContext, dan hubungan antarpenyedia dapat disusun sehingga satu penyedia dapat membaca penyedia lain sebagai nilai turunan. Package ini dibuat oleh pengembang yang sama dengan package Provider, dan banyak keputusan rancangannya lahir dari pengalaman mengembangkan package Provider itu sendiri.
// tidak-dijalankan
final daftarBelanjaProvider = Provider<List<String>>((ref) {
return <String>[];
});Penyedia yang dideklarasikan di atas tidak perlu dipasang di atas MaterialApp, karena pencariannya tidak melewati pohon widget. Keuntungan yang paling sering disebut adalah keamanan saat kompilasi. Kesalahan seperti mengakses penyedia yang tidak ada atau membaca penyedia di tempat yang salah tertangkap kompiler, bukan muncul sebagai ProviderNotFoundException saat aplikasi berjalan. Trade-off yang menyertainya adalah model konsep baru di luar model widget, yaitu ref dan grafik penyedia, sehingga dua cara berpikir perlu dikuasai bersamaan pada tahap awal.
Bloc#
Bloc mengatur pengelolaan state sebagai aliran yang eksplisit dari event ke state. Setiap perubahan bermula dari objek event, misalnya TugasDitandaiSelesai, dan penerima event memetakan event tersebut menjadi state baru. Rantai ini membuat jejak perubahan dapat dibaca dari luar, karena daftar event yang masuk dan state yang dihasilkannya direkam secara berurutan, sehingga perilaku aplikasi mudah diperiksa dan diuji tanpa perlu menjalankan antarmuka.
Struktur yang eksplisit itu menuntut kode boilerplate yang lebih banyak, yaitu kode pendukung yang harus ditulis berulang untuk setiap fitur. Satu interaksi sederhana menuntut kelas event, kelas state, dan pemetaan di antara keduanya, sehingga untuk layar yang kecil jumlah kode terasa tidak sebanding dengan pekerjaannya. Package yang sama menyediakan Cubit sebagai varian ringkas yang mengubah state langsung melalui method tanpa kelas event, dan Bloc penuh tetap tersedia untuk alur yang benar-benar membutuhkan jejak event.
Redux#
Redux membawa satu prinsip yang paling ketat di antara ketiganya, yaitu seluruh state aplikasi disimpan pada satu store, objek tunggal yang isinya hanya berubah melalui jalur yang ditetapkan. Perubahan dinyatakan sebagai action, objek kecil yang mendeskripsikan apa yang terjadi, dan reducer, yaitu fungsi murni yang menerima state lama beserta action lalu menghasilkan state baru tanpa mengubah objek mana pun. Tidak ada bagian aplikasi lain yang boleh menyunting state secara langsung.
Di Flutter, package flutter_redux mengikat store tersebut ke pohon widget melalui mekanisme rebuild yang serupa dengan mekanisme yang sudah dipelajari. Kekuatan utamanya adalah kepastian, karena setiap perubahan state selalu melewati action dan reducer yang sama, sehingga aliran data satu arah tidak mungkin dilewati. Biayanya adalah kode boilerplate yang paling besar di antara pendekatan yang dibahas, karena satu perubahan kecil menyentuh action, reducer, dan pengikat widgetnya.
Kapan Provider sudah memadai#
Pendekatan pada tiga bagian di atas berbeda pada beberapa aspek, tetapi pekerjaan dasarnya sama, yaitu menyimpan state, memberi tahu widget, dan membatasi bagian yang dibangun ulang. Untuk aplikasi kecil hingga menengah dengan jumlah state lintas layar yang masih sedikit, kombinasi ChangeNotifier, ChangeNotifierProvider, dan Consumer atau Selector yang sudah dipraktikkan menyelesaikan pekerjaan itu tanpa menambah konsep baru. Basisnya adalah mekanisme InheritedWidget milik framework sendiri, sehingga perilakunya dapat dijelaskan tanpa lapisan abstraksi tambahan.
Pergantian alat juga bukan keputusan sekali jadi untuk seluruh proyek. Karena seluruh pendekatan menggunakan prinsip pemberitahuan dan rebuild yang sama, pendekatan pada satu fitur dapat diganti tanpa memengaruhi fitur lain. Pilihan yang paling mahal biasanya bukan pilihan yang keliru, melainkan pilihan yang dibawa masuk lebih awal dari kebutuhannya.
Perbandingan singkat#
Tabel berikut merangkum perbandingan yang sudah dibahas pada bagian-bagian di atas.
| Pendekatan | Inti model | Kekuatan utama | Biaya yang menyertainya |
|---|---|---|---|
| Provider | pemberitahuan di atas InheritedWidget | ringan, dekat dengan framework | cakupan rebuild diatur manual, kesalahan penyedia terlihat saat berjalan |
| Riverpod | penyedia di luar pohon widget | aman saat kompilasi, penyedia dapat disusun | model konsep tersendiri di luar model widget |
| Bloc | aliran event ke state yang eksplisit | setiap perubahan terlacak dan mudah diuji | kode boilerplate lebih banyak untuk fitur kecil |
| Redux | satu store dengan reducer murni | aliran data satu arah yang ketat dan dapat diprediksi | kode boilerplate paling besar untuk fitur kecil |
Baris pada tabel tidak menunjukkan urutan keunggulan. Tabel semacam ini paling berguna sebagai peta untuk membandingkan, yaitu menimbang kolom biaya yang masih dapat ditanggung proyek dan kolom kekuatan yang paling sesuai dengan bentuk kebutuhannya.
Ringkasan#
- Riverpod memindahkan penyedia keluar dari pohon widget sehingga kesalahan pencarian tertangkap saat kompilasi, dengan biaya model konsep baru.
- Bloc memetakan event ke state secara eksplisit, sehingga setiap perubahan terlacak, dengan biaya kode boilerplate yang lebih besar.
- Redux menyimpan seluruh state pada satu store yang hanya berubah melalui action dan reducer, dengan kode boilerplate yang paling besar.
- Untuk aplikasi kecil hingga menengah, kombinasi Provider yang sudah dipelajari umumnya sudah memadai, dan migrasi antarpendekatan bersifat per fitur.
Referensi#
- riverpod — pub.dev — Halaman resmi package Riverpod beserta gambaran pendekatan penyedianya.
- bloc — pub.dev — Halaman resmi package Bloc dan Cubit beserta dokumentasi aliran event ke state.
- flutter_redux — pub.dev — Halaman resmi pengikat Redux untuk Flutter beserta dokumentasinya.
- Approaches to state management — Flutter — Halaman resmi Flutter yang memetakan pendekatan pengelolaan state di ekosistem.