WidjectContainer

Dependency Injection package for Flutter

Simple DI package to help structure your Flutter application in loosely coupled components.

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

  1. Open your project’s pubspec.yaml file.

  2. Add a git package dependency:

    dependencies:
      # -------------------------- #
      # Your existing dependencies #
      # -------------------------- #
      widject_container:
        git:
          url: https://github.com/zlatancld/WidjectContainer
    
  3. Execute flutter pub get.

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 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

@zlatancld

License

MIT

GitHub

View Github