Flutter adalah framework pengembangan aplikasi yang powerful, tetapi salah satu tantangan terbesar bagi developer adalah memilih state management yang tepat. State management membantu mengelola data dan UI secara efisien, memastikan aplikasi tetap responsif dan mudah dikembangkan.
Pada blog kali ini, kita akan membahas beberapa state management populer di Flutter, kelebihan, kekurangan, serta rekomendasi berdasarkan kebutuhan proyek kalian.
1. Provider: Solusi Sederhana untuk Pemula
State management Provider adalah salah satu metode (atau pola) dalam pengelolaan state di aplikasi Flutter. Provider sendiri merupakan package resmi yang direkomendasikan oleh tim Flutter, karena ringan, efisien, dan mudah digunakan.
Package: provider
Kelebihan:
- Mudah dipahami dan digunakan.
- Direkomendasikan oleh tim Flutter.
- Cocok untuk proyek kecil hingga menengah.
Kekurangan:
❌ Kurang cocok untuk aplikasi kompleks dengan banyak state.
Kapan Menggunakan Provider?
- Jika kalian baru belajar state management.
- Untuk aplikasi dengan logika bisnis sederhana.
Ilustrasi sederhana:
1. Buat state-nya
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // kasih tahu UI untuk update
}
}
2. Daftarkan provider-nya di atas widget tree
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
),
);
}
3. Gunakan state di UI
class CounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context);
return Column(
children: [
Text('Count: ${counter.count}'),
ElevatedButton(
onPressed: counter.increment,
child: Text('Tambah'),
),
],
);
}
}
2. Riverpod: Pengganti Provider yang Lebih Kuat
Riverpod adalah salah satu state management (pengelola status/data) di Flutter, yang dirancang untuk menggantikan dan memperbaiki beberapa kekurangan dari Provider, yang merupakan pendahulunya. Riverpod menawarkan pendekatan yang lebih fleksibel, aman, dan mudah diuji untuk mengelola dan membagikan data antar bagian aplikasi Flutter.
Package: flutter_riverpod
Kelebihan:
- Tidak tergantung pada
BuildContext
.
- Lebih fleksibel dan aman dibanding Provider.
- Cocok untuk testing dan dependency injection.
Kekurangan:
❌ Kurva belajar sedikit lebih tinggi.
Kapan Menggunakan Riverpod?
- Jika kalian butuh solusi lebih kuat dari Provider.
- Untuk proyek menengah hingga besar.
Contoh Penggunaan Sederhana:
1. Tambahkan dependency:
dependencies:
flutter_riverpod: ^2.0.0
2. Buat Provider:
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateProvider<int>((ref) => 0);
3. Gunakan di UI:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp())); // Wrap app with ProviderScope
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
class HomePage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: Text('Riverpod Example')),
body: Center(child: Text('Count: $count')),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Icon(Icons.add),
),
);
}
}
3. Bloc: State Management untuk Aplikasi Kompleks
State management BLoC (singkatan dari Business Logic Component) di Flutter adalah sebuah pola arsitektur yang memisahkan logika bisnis (business logic) dari tampilan (UI). Tujuannya adalah untuk membuat kode menjadi lebih terstruktur, terpisah, dan mudah diuji.
Konsep Inti BLoC
Di dalam BLoC, ada tiga komponen utama:
- Event
Representasi aksi yang dilakukan oleh user atau sistem (misalnya:
AddToCart
, LoadProduct
, SubmitOrder
).
- State
Representasi kondisi aplikasi pada satu waktu tertentu (misalnya:
CartLoading
, CartLoaded
, CartError
).
- Bloc
Komponen yang menerima event, memproses logika, dan mengeluarkan state baru berdasarkan event tersebut.
Package: flutter_bloc
Kelebihan:
- Memisahkan logika bisnis dari UI dengan jelas.
- Cocok untuk aplikasi besar dengan banyak interaksi.
Kekurangan:
❌ Membutuhkan lebih banyak boilerplate.
Kapan Menggunakan Bloc?
- Jika kalian mengembangkan aplikasi enterprise.
- Ketika membutuhkan manajemen state yang terstruktur.
Contoh Gampang (CartBloc)
Misalnya kamu punya fitur keranjang:
Event:
abstract class CartEvent {}
class AddItemToCart extends CartEvent {
final String productId;
AddItemToCart(this.productId);
}
State:
abstract class CartState {}
class CartInitial extends CartState {}
class CartLoading extends CartState {}
class CartLoaded extends CartState {
final List<String> items;
CartLoaded(this.items);
}
Bloc:
class CartBloc extends Bloc<CartEvent, CartState> {
List<String> _cartItems = [];
CartBloc() : super(CartInitial()) {
on<AddItemToCart>((event, emit) {
emit(CartLoading());
_cartItems.add(event.productId);
emit(CartLoaded(List.from(_cartItems)));
});
}
}
Di UI:
BlocBuilder<CartBloc, CartState>(
builder: (context, state) {
if (state is CartLoading) {
return CircularProgressIndicator();
} else if (state is CartLoaded) {
return ListView(
children: state.items.map((item) => Text(item)).toList(),
);
}
return Text('Keranjang kosong');
},
);
4. GetX: Solusi Cepat dengan Minimal Boilerplate
State management GetX di Flutter adalah salah satu pendekatan populer untuk mengelola state (keadaan/data) aplikasi, serta routing dan dependency injection dengan cara yang mudah, cepat, dan efisien. GetX menjadi pilihan banyak developer karena sintaksnya yang simpel dan performanya yang baik.
Package: get
Kelebihan:
- Sangat ringan dan mudah digunakan.
- Mendukung navigasi, dependency injection, dan state management.
Kekurangan:
❌ Kurang terstruktur untuk proyek besar.
Kapan Menggunakan GetX?
- Untuk prototyping cepat.
- Jika ingin mengurangi boilerplate.
GetX dalam State Management
GetX menyediakan beberapa cara untuk mengelola state:
-
Reactive State (Obx)
-
Gunakan variabel Rx (Reactive), lalu bungkus UI dengan Obx
untuk mendeteksi perubahan otomatis.
-
Contoh:
class CounterController extends GetxController {
var count = 0.obs; // .obs membuat variabel jadi observable
void increment() {
count++;
}
}
// Di UI
final controller = Get.put(CounterController());
Obx(() => Text("Count: ${controller.count}"));
-
Simple State (update())
-
Gunakan dengan GetBuilder
, cocok untuk state yang tidak terlalu kompleks.
-
Contoh:
class CounterController extends GetxController {
int count = 0;
void increment() {
count++;
update(); // memicu update UI
}
}
// Di UI
GetBuilder<CounterController>(
init: CounterController(),
builder: (controller) => Text("Count: ${controller.count}"),
);
-
Dependency Injection
-
GetX juga bisa menyuntikkan dan mengatur controller dengan sangat mudah.
-
Contoh:
final controller = Get.put(CounterController()); // dibuat sekali, bisa dipakai di mana-mana
-
Routing
5. MobX: Reactive Programming di Flutter
MobX adalah salah satu state management library di Flutter yang digunakan untuk mengelola dan mengamati perubahan state secara reaktif. MobX diambil dari dunia JavaScript (React) dan diadaptasi untuk Flutter dengan pendekatan reactive programming.
Konsep Inti MobX di Flutter:
- Observable (State):
Ini adalah data yang bisa berubah dan bisa diamati. Contoh: variabel counter, list produk, dll.
- Action:
Fungsi yang mengubah observable. Semua perubahan state sebaiknya dibungkus dalam action agar MobX bisa melacak perubahan dengan jelas.
- Reaction:
Efek samping yang dijalankan ketika observables berubah. Contohnya seperti rebuild UI saat data berubah.
- Computed:
Nilai yang dihitung dari observables lainnya. Contoh:
isCartEmpty
bisa dihitung dari cartItems.isEmpty
.
Package: mobx
Kelebihan:
- Reactive programming dengan sedikit boilerplate.
- Cocok untuk developer yang suka pendekatan observables.
Kekurangan:
❌ Membutuhkan code generation (build_runner
).
Kapan Menggunakan MobX?
- Jika kalian familiar dengan reactive programming.
- Untuk aplikasi yang membutuhkan reaktivitas tinggi.
Cara Kerja:
Kamu menandai variabel sebagai @observable
, lalu ubah nilainya lewat @action
, dan UI otomatis akan rebuild jika kamu menggunakan Observer
.
Contoh Sederhana:
1. Tambahkan Dependency:
dependencies:
flutter_mobx: ^2.0.6
mobx: ^2.0.6
dev_dependencies:
build_runner: ^2.1.7
mobx_codegen: ^2.0.5
2. Buat Store (state-nya):
import 'package:mobx/mobx.dart';
part 'counter_store.g.dart';
class CounterStore = _CounterStore with _$CounterStore;
abstract class _CounterStore with Store {
@observable
int counter = 0;
@action
void increment() {
counter++;
}
}
Lalu jalankan perintah:
flutter pub run build_runner build
3. Gunakan di UI:
final counterStore = CounterStore();
Observer(
builder: (_) => Text('${counterStore.counter}'),
)
ElevatedButton(
onPressed: () => counterStore.increment(),
child: Text('Tambah'),
)
6. Redux: State Management Terpusat
Redux di Flutter adalah state management pattern yang diadaptasi dari Redux di JavaScript (terutama React). Dia fokus pada konsep satu sumber kebenaran (single source of truth), state yang tidak bisa diubah langsung (immutable), dan alur data satu arah (unidirectional flow).
Konsep Inti Redux:
- Store:
Tempat semua state disimpan. Hanya ada satu store utama.
- State:
Representasi dari semua data aplikasi kamu. State itu immutable, jadi nggak boleh diubah langsung.
- Action:
Objek yang mendeskripsikan apa yang ingin dilakukan (misalnya:
{ type: 'ADD_TODO' }
).
- Reducer:
Fungsi yang menerima
state
dan action
, lalu mengembalikan state baru.
- Middleware (opsional):
Tempat untuk menangani side-effects seperti API call, logging, dll.
Alur Redux:
UI (View)
↓
Dispatch(Action)
↓
Reducer (mengubah state)
↓
Store (update state)
↓
UI rebuild berdasarkan state baru
Package: flutter_redux
Kelebihan:
- Cocok untuk state global yang kompleks.
- Memudahkan debugging dengan sistem yang terprediksi.
Kekurangan:
❌ Boilerplate tinggi.
Kapan Menggunakan Redux?
- Jika kalian butuh state management yang sangat terstruktur.
- Untuk aplikasi dengan banyak shared state.
Contoh Sederhana Redux di Flutter
1. Tambahkan dependency:
dependencies:
flutter_redux: ^0.10.0
redux: ^5.0.0
2. Definisikan State:
class CounterState {
final int count;
CounterState(this.count);
}
3. Definisikan Action:
class IncrementAction {}
4. Buat Reducer:
CounterState counterReducer(CounterState state, dynamic action) {
if (action is IncrementAction) {
return CounterState(state.count + 1);
}
return state;
}
5. Buat Store:
final store = Store<CounterState>(
counterReducer,
initialState: CounterState(0),
);
6. Gunakan di UI:
void main() {
runApp(MyApp(store: store));
}
class MyApp extends StatelessWidget {
final Store<CounterState> store;
MyApp({required this.store});
@override
Widget build(BuildContext context) {
return StoreProvider(
store: store,
child: MaterialApp(
home: CounterPage(),
),
);
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StoreConnector<CounterState, int>(
converter: (store) => store.state.count,
builder: (context, count) => Text('$count'),
),
),
floatingActionButton: StoreConnector<CounterState, VoidCallback>(
converter: (store) => () => store.dispatch(IncrementAction()),
builder: (context, callback) => FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
),
),
);
}
}
Kesimpulan: State Management Mana yang Harus Dipilih?
Kebutuhan |
State Management |
Pemula / Proyek kecil |
Provider / GetX |
Proyek menengah-besar |
Riverpod / Bloc |
Reactive programming |
MobX |
State global terpusat |
Redux |
Prototyping cepat |
GetX |
Tips Memilih State Management:
- Pelajari Provider atau Riverpod jika kalia baru memulai.
- Gunakan Bloc/Riverpod untuk proyek besar dan terstruktur.
- Pilih GetX jika ingin pengembangan cepat dengan sedikit kode.
Dengan memilih state management yang tepat, kalian dapat meningkatkan maintainability, performa, dan skalabilitas aplikasi Flutter kalian. 🚀
Apa state management favorit teman-teman? Bagikan di komentar! 💬