get_light 1.0.2
get_light: ^1.0.2 copied to clipboard
Lightweight Flutter state management and dependency injection from GetX, with reactive variables, simple state, dependency injection, and worker utilities.
get_light #
Lightweight Flutter state management and dependency injection, extracted from GetX.
Keeps only the essential pieces — reactive state, simple state, and DI — with no routing or utility overhead.
Features #
| Feature | API |
|---|---|
| Reactive variables | .obs, Rx<T>, RxInt, RxBool, RxList, … |
| Reactive widget | Obx(() => ...) |
| Simple state | GetxController + update() + GetBuilder |
| Dependency injection | Get.put, Get.lazyPut, Get.find, Get.delete |
| Reactive workers | ever, once, debounce, interval |
| Controller lifecycle | onInit, onReady, onClose |
| Permanent services | GetxService |
Installation #
dependencies:
get_light: ^1.0.0
import 'package:get_light/get_light.dart';
Reactive state #
Append .obs to any value to make it reactive. Wrap the UI in Obx to rebuild automatically.
class CounterController extends GetxController {
final count = 0.obs;
void increment() => count.value++;
}
final ctrl = Get.put(CounterController());
Obx(() => Text('${ctrl.count}'))
Reactive types #
| Type | Shorthand |
|---|---|
Rx<T> |
value.obs |
RxInt |
0.obs |
RxDouble |
0.0.obs |
RxBool |
false.obs |
RxString |
''.obs |
RxList<T> |
RxList<T>() |
RxMap<K,V> |
RxMap<K,V>() |
RxSet<T> |
RxSet<T>() |
Simple state #
Use update() instead of .obs when you prefer explicit control over rebuilds.
class CounterController extends GetxController {
int count = 0;
void increment() {
count++;
update(); // rebuilds all GetBuilder widgets bound to this controller
update(['card']); // rebuilds only widgets with id: 'card'
}
}
GetBuilder<CounterController>(
init: CounterController(),
builder: (ctrl) => Text('${ctrl.count}'),
)
Dependency injection #
// Register
Get.put(AuthService()); // eager singleton
Get.lazyPut<ApiService>(() => ApiService()); // created on first find
Get.create<Repo>(() => Repo()); // new instance every find
// Retrieve
final svc = Get.find<AuthService>();
final svc = Get.findOrNull<AuthService>(); // null if not registered
// Inspect
Get.isRegistered<AuthService>();
Get.isPrepared<ApiService>(); // true = lazyPut not yet built
// Remove
Get.delete<AuthService>();
Get.deleteAll();
Tags #
Use tag to register multiple instances of the same type:
Get.put(ApiService(baseUrl: 'https://api.example.com'), tag: 'prod');
Get.put(ApiService(baseUrl: 'https://staging.example.com'), tag: 'staging');
final prod = Get.find<ApiService>(tag: 'prod');
Services #
GetxService is a permanent singleton that survives deleteAll() unless force: true is passed.
class AuthService extends GetxService {
final token = ''.obs;
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
Get.put(AuthService(), permanent: true);
runApp(MyApp());
}
Controller lifecycle #
class MyController extends GetxController {
@override
void onInit() {
super.onInit();
// called immediately when the controller is created
}
@override
void onReady() {
// called one frame after onInit (post-frame callback)
}
@override
void onClose() {
// called when the controller is removed from memory
super.onClose();
}
}
Workers #
Workers observe a GetListenable (any .obs variable) and run a callback on changes.
Always dispose workers in onClose.
class SearchController extends GetxController {
final query = ''.obs;
final results = RxList<String>();
Worker? _debouncer;
Worker? _logger;
@override
void onInit() {
super.onInit();
// runs on every change
_logger = ever(query, (val) => print('query: $val'));
// runs once, when the condition is first met
once(query, (val) => print('first search: $val'),
condition: () => query.value.isNotEmpty);
// fires at most once per 500 ms
_debouncer = debounce(query, _search,
time: const Duration(milliseconds: 500));
}
void _search(String val) { /* call API */ }
@override
void onClose() {
_debouncer?.dispose();
_logger?.dispose();
super.onClose();
}
}
| Worker | Behaviour |
|---|---|
ever |
Every change |
once |
First change that meets the condition |
interval |
First change, then ignores changes for time |
debounce |
Last change after time of silence |
GetView #
GetView<T> is a stateless widget with a built-in controller getter — a shortcut when a screen always maps 1-to-1 to a controller.
class CounterPage extends GetView<CounterController> {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Obx(() => Text('${controller.count}')),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: const Icon(Icons.add),
),
);
}
}
Differences from GetX #
| get_light | get | |
|---|---|---|
| Routing | — | ✓ |
| Translations / i18n | — | ✓ |
| Utils (validator, extensions) | — | ✓ |
| State management | ✓ | ✓ |
| Dependency injection | ✓ | ✓ |
| Workers | ✓ | ✓ |
| Pub.dev dependency count | 1 (flutter) | many |
License #
MIT — see LICENSE.