GetX Extensions – RxCubit, Listener, Consumer
Extend GetX with a Cubit/Bloc-style API, inspired by flutter_bloc, but with GetX simplicity.
🚀 Features
RxCubit: Manage state withemit.RxState: Base class for states.- Built-in generic states:
RxInitialRxLoadingRxSuccess<T>RxError
GetXListener: Listen for state changes (side effects only).GetXConsumer: Listen and rebuild UI in one widget.
📦 Installation
Add to your pubspec.yaml:
dependencies:
getx_exten: ^1.1.5
🔧 Base States
RxState (Base Class)
abstract class RxState {
const RxState();
}
Generic States
class RxInitial extends RxState {}
class RxLoading extends RxState {}
class RxSuccess<T> extends RxState {
final T data;
const RxSuccess(this.data);
}
class RxError extends RxState {
final String message;
const RxError(this.message);
}
📝 Example: Counter Cubit
State
abstract class CounterState extends RxState {
final int value;
const CounterState(this.value);
}
class CounterInitial extends CounterState {
const CounterInitial() : super(0);
}
class CounterValue extends CounterState {
const CounterValue(int value) : super(value);
}
Controller
class CounterController extends RxCubit<CounterState> {
CounterController() : super(const CounterInitial());
void increment() => emit(CounterValue(state.value + 1));
void reset() => emit(const CounterInitial());
}
UI
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.put(CounterController());
return Scaffold(
appBar: AppBar(title: const Text("Counter Example")),
body: Center(
child: GetXConsumer<CounterState>(
observable: controller.state\$,
builder: (context, state) {
if (state is CounterValue) {
return Text(
"Count: \${state.value}",
style: const TextStyle(fontSize: 32),
);
}
return const Text("Press + to start");
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: const Icon(Icons.add),
),
);
}
}
🎧 Listener Example
GetXListener<CounterState>(
observable: controller.state\$,
listenWhen: (prev, curr) => curr is CounterValue && curr.value == 5,
listener: (context, state) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("🎉 Count reached 5!")),
);
},
child: GetXConsumer<CounterState>(
observable: controller.state\$,
builder: (context, state) {
final value = state is CounterValue ? state.value : 0;
return Text("Count: \$value", style: const TextStyle(fontSize: 28));
},
),
)
🔄 API Fetching Example
Controller
class ApiController extends RxCubit<RxState> {
ApiController() : super(const RxInitial());
@override
void onInit(){
super.onInit();
fetchItems();
}
Future<void> fetchItems() async {
emit(const RxLoading());
await Future.delayed(const Duration(seconds: 2));
try {
final items = ["Apple", "Banana", "Mango"];
emit(RxSuccess(items));
} catch (e) {
emit(RxError("Failed to fetch data"));
}
}
}
UI
GetXConsumer<RxState>(
observable: apiController.state,
builder: (context, state) {
if (state is RxLoading) {
return const CircularProgressIndicator();
} else if (state is RxSuccess<List<String>>) {
return Column(
children: state.data.map((e) => Text(e)).toList(),
);
} else if (state is RxError) {
return Text("Error: ${state.message}");
}
return const Text("Press fetch to load items");
},
)
Libraries
- get_consumer/get_consumer
- get_listener/get_listener
- getx_exten
- Support for doing something awesome.
- utils/base_state
- utils/emit