Episode ini naik kelas ke state management skala menengah: memilih dan memakai pattern Provider, Riverpod, Bloc, GetX, dan MobX, memahami reactive state flow dan dependency injection, mengelola state kompleks dengan modularization, serta kriteria memilih arsitektur sesuai ukuran aplikasi.

setState dan Provider cukup untuk aplikasi kecil, tetapi saat fitur bertambah — auth, keranjang belanja, sinkronisasi, notifikasi — state management harus diorganisasi dengan disiplin. Episode 10 membandingkan pattern yang paling banyak dipakai komunitas dan membantu kalian memilih dengan alasan, bukan ikut-ikutan.
Kita membahas Provider, Riverpod, Bloc, GetX, dan MobX, memahami reactive state flow dan dependency injection, teknik modularization untuk state kompleks, serta kerangka berpikir memilih arsitektur berdasarkan ukuran dan tim.
flutter pub add flutter_riverpodDengan Riverpod, state didefinisikan sebagai provider terpisah dari widget:
final counterProvider = StateProvider<int>((ref) => 0);
class CounterScreen extends ConsumerWidget {
const CounterScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Nilai: $count');
}
}StateProvider menyimpan nilai sederhana dan ref.watch(counterProvider) membuat widget bereaksi terhadap perubahannya. ConsumerWidget menggantikan StatelessWidget untuk widget yang mengonsumsi provider.
Semua pattern di atas mengikuti prinsip unidirectional data flow: state menghasilkan UI, interaksi menghasilkan event, event mengubah state, lalu siklus berulang. Kesalahan paling umum adalah memutasi state dari sembarang tempat tanpa jalur yang jelas.
Provider bukan hanya untuk state — juga untuk membagikan object seperti repository atau client HTTP:
final postRepositoryProvider = Provider<PostRepository>((ref) {
return PostRepository(httpClient: dio);
});postRepositoryProvider membangun PostRepository sekali dan membagikannya ke seluruh aplikasi. Ini adalah dependency injection sederhana: widget menerima dependensi lewat provider, bukan membuatnya sendiri, sehingga mudah ditimpa dengan mock saat testing.
Aplikasi menengah membutuhkan pemisahan state per domain:
AuthController — sesi dan token.CartController — isi keranjang.OrderController — status pesanan.Jangan satukan semua state dalam satu object raksasa. Setiap fitur punya provider atau controller sendiri, dan layar mengonsumsi hanya yang dibutuhkannya.
class CartController extends ChangeNotifier {
final List<Item> _items = [];
int get totalBarang => _items.length;
void tambah(Item item) {
_items.add(item);
notifyListeners();
}
}CartController mengelola satu tanggung jawab. Dengan pola ini, perubahan satu domain tidak mengguncang domain lain — kunci maintainability.
Semakin halus granularity provider, semakin sedikit widget yang rebuild saat state berubah. Aturan praktis: dengarkan di level terkecil. Jangan watch state besar di root jika hanya satu nilai yang dipakai — ini penyebab jank yang akan kita bahas di episode 15.
Panduan memilih pattern:
flutter pub deps --style=compactflutter pub deps --style=compact menampilkan pohon dependency dalam satu baris per package — praktis untuk memeriksa apa saja yang sudah masuk sebelum menambah pattern baru.
Arsitektur terbaik adalah yang dipahami seluruh tim. Apapun pilihan kalian, dokumentasikan alur state di README, gunakan satu pattern secara konsisten, dan jangan mencampur tiga pattern dalam satu project tanpa alasan. Episode 20 akan memetakan ini ke arsitektur berskala production.
Inti yang harus dibawa pulang:
Di episode 11 selanjutnya kita membahas navigation dan app architecture — perbedaan Navigator 1.0 dan Navigator 2.0, named routes, nested routes, dan deep linking, modular app architecture dan feature modules, serta code organization dan separation of concerns. Struktur project kalian mulai beranjak ke skala nyata.