A minimal state solution based on my Pragmatic state handling in Flutter Medium article .
A set of classes built on ValueNotifier
and ValueListenableBuilder
for
handling state in Flutter.
MuState
- an alias forValueNotifier
where you can optionally use aMuEvent<T>
typeMuBuilder
- an alias forValueListenableBuilder
MuEvent<T>
- the base class for 3 state objects which can be used in aMuState<T>
:MuData<T>
- the data state of typeT
MuError
- the error stateMuLoading
- the loading state
MuMultiBuilder
- listen to changes of a list ofListenable
objects
Contain state by inheriting from MuState
or using it directly. This can have any type.
You can optionally use MuEvent
types: MuLoading
, MuError
or MuData
to contain state.
Listen to MuState
changes using MuBuilder
.
Listen to multiple MuState
objects using MuMultiBuilder
.
A simple counter state:
import 'package:mu_state/mu_state.dart';
class CounterState extends MuState<int> {
CounterState(super.initValue);
void increment() {
value = value + 1;
}
}
final counterState = CounterState(0);
In main.dart
:
Scaffold(
body: Center(
child: MuBuilder(
valueListenable: counterState,
builder: (context, event, child) {
return Text('$value');
},
),
),
),
A state with loading and error handling:
class LoadState extends MuState<MuEvent<String>> {
LoadState(super.value);
void load() async {
value = const MuLoadingEvent();
await Future.delayed(const Duration(milliseconds: 500));
value = const MuDataEvent('done');
}
}
final loadState = LoadState(const MuDataEvent('initial'));
Handle loading and error states:
Scaffold(
body: Center(
child: MuBuilder(
valueListenable: loadState,
builder: (context, event, child) {
return switch (event) {
MuLoadingEvent() => const CircularProgressIndicator(),
MuErrorEvent() => Text('Error: ${event.error}'),
MuDataEvent() => Text('Data: ${event.data}'),
};
},
),
),
),
See more examples in Example.