widject_container 1.0.2 widject_container: ^1.0.2 copied to clipboard
Dependency Injection Container to structure your application in loosely coupled components. Inspired by VContainer.
WidjectContainer #
Dependency Injection package for Flutter
Simple DI package to help structure your Flutter application in loosely coupled components. Inspired by VContainer.
Features #
- Explicit constructor injection within scopes.
- No use of reflection/mirrors.
- Nested scope support to isolate dependencies by widget type.
- Async initialization of scoped dependencies.
Installation #
Add the package with the command: flutter pub add widject_container
or adding widject_container
to your project's pubspec.yaml dependencies.
Basic Usage #
Create a scope connected to a widget and register the required types. The type references are automatically resolved when requested within the scope.
class AppScope extends Scope<AppWidget> {
AppScope(): super(null);
@override
void configure(ContainerRegister register) {
register.add((r) => HelloWorldProvider(), Lifetime.transient).as<MessageProvider>();
register.addWidget((r, key, _) => AppWidget(r.get(), key: key));
}
}
Where classes are:
abstract class MessageProvider {
String getMessage();
}
class HelloWorldProvider implements MessageProvider {
@override
String getMessage()
=> "Hello world!";
}
class AppWidget extends StatelessWidget {
final MessageProvider _messageProvider;
const AppWidget(this._messageProvider, {super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WidjectContainer Demo',
home: Scaffold(
body: Text(_messageProvider.getMessage())
)
);
}
}
Example of scope usage in main function is:
void main() {
var app = AppScope().getWidget();
runApp(app);
}
Widget Provider #
Use WidgetProvider
to instantiate widget types that have been registered within a scope. Dependencies are resolved and explicitly injected, as defined in the scope registration.
Example of registration:
class AppScope extends Scope<AppWidget> {
...
@override
void configure(ContainerRegister register) {
...
register.addWidget((r, key, _) => NewWidget(r.get(), args, key: key));
}
}
Example of usage through WidgetProvider
:
class AppWidget extends StatelessWidget {
final MessageProvider _messageProvider;
final WidgetProvider _widgetProvider;
const AppWidget(this._messageProvider, this._widgetProvider, {super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WidjectContainer Demo',
home: Scaffold(
body: _widgetProvider.getWidget<NewWidget>())
)
);
}
}
Nested Scopes #
Connect the instantiation of a widget to a new scope, registering types and inheriting references from ancestor scopes. This can be useful when creating a new screen that requires a whole new set of dependencies.
class ScreenScope extends Scope<ScreenWidget>{
ScreenScope(super.parentContainer);
@override
void configure(ContainerRegister register) {
register.addWidget((r, key, args) => ScreenWidget(...));
}
}
Where the scoped widget binding in the parent scope is:
class AppScope extends Scope<AppWidget> {
...
@override
void configure(ContainerRegister register) {
...
register.addScopedWidget((r, key, _) => ScreenScope(r));
}
}
Example of usage through WidgetProvider
:
class AppWidget extends StatelessWidget {
final MessageProvider _messageProvider;
final WidgetProvider _widgetProvider;
const AppWidget(this._messageProvider, this._widgetProvider, {super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WidjectContainer Demo',
home: Scaffold(
body: TextButton(
onPressed: () => _openChildWidget(context),
child: Text(_messageProvider.getMessage()))));
}
_openChildWidget(BuildContext context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => _widgetProvider.getWidget<ScreenWidget>()));
}
}
Credits #
WidjectContainer is inspired by:
Author #
License #
MIT