lite_ref
一个轻量级的 Dart 和 Flutter 依赖注入库。
- 星标
- 19
- 复刻
- 3
- 最近推送(UTC)
- 2024年11月15日
- 项目状态
- 未归档
原始 README
以下为英文项目原文快照,最新内容请访问 GitHub。

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(), ),
A ScopedFamilyRef is used when you need to create a unique instance for different keys.
This is useful for creating multiple instances of the same class with different configurations.
-
Create a
ScopedFamilyRef.final postControllerRef = Ref.scopedFamily((ctx, String key) { return PostController(key)..fetch(); }); -
Access the instance in the current scope:
This can be done in a widget by using
postController.of(context, key)orpostController(context, key).class PostsPage extends StatelessWidget { const PostsPage({required this.keys, super.key}); final List<String> keys; @override Widget build(BuildContext context) { return ListView.builder( itemBuilder: (context, index) { final post = postControllerRef.of(context, keys[index]); return Text(post?.title ?? 'Loading...'); }, ); } }
Disposal
When a ScopedRef provides a ChangeNotifier, ValueNotifier or a class that implements Disposable, it will automatically dispose the instance when all the widgets that have access to the instance are unmounted.
In the example below, the CounterController will be disposed when the CounterView is unmounted.
class CounterController extends ChangeNotifier {
var _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void decrement() {
_count--;
notifyListeners();
}
}
final countControllerRef = Ref.scoped((ctx) => CounterController());
class CounterView extends StatelessWidget {
const CounterView({super.key});
@override
Widget build(BuildContext context) {
final controller = countControllerRef.of(context);
return ListenableBuilder(
listenable: controller,
builder: (context, snapshot) {
return Text('${controller.count}');
},
);
}
}
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;
分类
如何选择适合项目的代码仓?
先按使用场景筛选,再比较项目活跃情况,最后到原始仓库核对使用要求。
- 通过仓库名、作者或描述搜索,再按技术分类缩小范围。
- 结合星标、复刻与最近推送比较项目;星标反映社区关注,不代表质量保证。
- 使用前在 GitHub 核对 README、许可证与 Issues。
来源与维护
“A repository is the most basic element of GitHub.”
GitHub Docs — About repositories ↗