lite_ref 0.4.0
lite_ref: ^0.4.0 copied to clipboard
A lightweight dependency injection package with support for overriding for testing.
Overview #
Lite Ref is a lightweight dependency injection library for Dart and Flutter.
Installation #
dart pub add lite_ref
Why Lite Ref? #
- Fast: Doesn't use hashmaps to store instances so it's faster than all other DI libraries.
- Safe: Uses top level variables so it's impossible to get a NOT_FOUND error.
- Lightweight: Has no dependencies.
- Simple: Easy to learn with a small API surface
Scoped Refs #
A ScopedRef
is a reference that needs a build context to access its instance. This is an alternative to Provider
for classes that don't rebuild widgets. eg: Controllers, Repositories, Services, etc.
-
Wrap your app or a subtree with a
LiteRefScope
:runApp( LiteRefScope( child: MyApp(), ), );
-
Create a
ScopedRef
.final settingsServiceRef = Ref.scoped((ctx) => SettingsService());
-
Access the instance in the current scope:
This can be done in a widget by using
settingsServiceRef.of(context)
orsettingsServiceRef(context)
.class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override Widget build(BuildContext context) { final settingsService = settingsServiceRef.of(context); return Text(settingsService.getThemeMode()); } }
-
Override it for a subtree:
You can override the instance for a subtree by using
overrideWith
. This is useful for testing. In the example below, all calls tosettingsServiceRef.of(context)
will returnMockSettingsService
.LiteRefScope( overrides: [ settingsServiceRef.overrideWith((ctx) => MockSettingsService()), ] child: MyApp(), ),
Click here for a flutter example with testing. #
Global Singletons and Transients #
-
Create a singleton:
final dbRef = Ref.singleton(() => Database()); assert(dbRef.instance == dbRef.instance);
-
Use it:
final db = dbRef.instance; // or dbRef()
-
Override it (for testing):
dbRef.overrideWith(() => MockDatabase());
-
Freeze it (disable overriding):
// overrideWith is marked as @visibleForTesting so this isn't really necessary. dbRef.freeze();
-
Create a transient instance (always return new instance):
final dbRef = Ref.transient(() => Database()); assert(dbRef.instance != dbRef.instance);
-
Create a singleton asynchronously:
final dbRef = Ref.asyncSingleton(() async => await Database.init());
-
Use it:
final db = await dbRef.instance;
-
Use it synchronously:
// only use this if you know the instance is already created final db = dbRef.assertInstance;