Macam-Macam State Management di Flutter:
1. setState()
Cara paling dasar, cocok untuk state lokal di satu widget.
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('$counter')),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => counter++),
child: Icon(Icons.add),
),
);
}
}
๐ Kelebihan: simpel.
๐ Kekurangan: sulit dipakai kalau state dibutuhkan banyak widget.
2. InheritedWidget / InheritedNotifier
Digunakan untuk share data antar widget tanpa library eksternal.
class CounterProvider extends InheritedNotifier<ValueNotifier<int>> {
CounterProvider({super.key, required Widget child})
: super(notifier: ValueNotifier(0), child: child);
static ValueNotifier<int> of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<CounterProvider>()!.notifier!;
}
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CounterProvider(
child: Builder(builder: (context) {
final counter = CounterProvider.of(context);
return Scaffold(
body: Center(child: ValueListenableBuilder(
valueListenable: counter,
builder: (_, value, __) => Text('$value'),
)),
floatingActionButton: FloatingActionButton(
onPressed: () => counter.value++,
child: Icon(Icons.add),
),
);
}),
);
}
}
๐ Lebih fleksibel dari setState, tapi verbose.
3. Provider
Library paling populer, resmi didukung Google.
class Counter with ChangeNotifier {
int value = 0;
void increment() {
value++;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<Counter>();
return Scaffold(
body: Center(child: Text('${counter.value}')),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<Counter>().increment(),
child: Icon(Icons.add),
),
);
}
}
๐ Cocok untuk skala menengah.
4. Riverpod
Versi modern dari Provider, lebih aman dan tidak bergantung pada BuildContext.
final counterProvider = StateProvider<int>((ref) => 0);
class CounterApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
return Scaffold(
body: Center(child: Text('$counter')),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Icon(Icons.add),
),
);
}
}
๐ Lebih clean, testable, cocok untuk proyek besar.
5. BLoC (Business Logic Component)
Arsitektur berbasis event & stream, sangat cocok untuk aplikasi enterprise.
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
}
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CounterCubit(),
child: BlocBuilder<CounterCubit, int>(
builder: (context, counter) {
return Scaffold(
body: Center(child: Text('$counter')),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: Icon(Icons.add),
),
);
},
),
);
}
}
๐ Skalabel, tapi banyak boilerplate.
6. GetX
Ringkas, reactive, dan cepat.
class CounterController extends GetxController {
var counter = 0.obs;
void increment() => counter++;
}
class CounterApp extends StatelessWidget {
final c = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Obx(() => Text('${c.counter}'))),
floatingActionButton: FloatingActionButton(
onPressed: c.increment,
child: Icon(Icons.add),
),
);
}
}
๐ Cepat, minim boilerplate.
๐ Tapi bisa sulit di-maintain jika terlalu kompleks.
Kesimpulan
setState โ simple UI lokal.
InheritedWidget โ share data tanpa package.
Provider โ standar populer.
Riverpod โ modern, fleksibel.
BLoC โ enterprise & arsitektur ketat.
GetX โ cepat, praktis, minimalis.