inject_flutter

Flutter-specific extension for inject.dart that simplifies ViewModel injection and lifecycle management to promote cleaner architecture in Flutter apps.

Features

  • Automatic ViewModel Lifecycle Management: Create and dispose ViewModels automatically with widget lifecycle
  • Clean Widget Architecture: Separate business logic from UI code
  • Reactive UI Updates: Widgets automatically rebuild when ViewModel state changes
  • Seamless Integration: Works directly with inject.dart's dependency injection system
  • Type-safe: Compile-time checking ensures your dependencies are correctly configured

Installation

Add these dependencies to your pubspec.yaml:

dependencies:
  inject_annotation: <current version>
  inject_flutter: <current version>

dev_dependencies:
  inject_generator: <current version>
  build_runner: <current version>

You can archive this by running flutter pub add inject_annotation inject_flutter dev:inject_generator dev:build_runner

Usage

1. Create a ViewModel

First, create a ViewModel that extends ChangeNotifier:

import 'package:flutter/foundation.dart';
import 'package:inject_annotation/inject_annotation.dart';

@inject
class HomePageViewModel extends ChangeNotifier {
  int count = 0;

  void incrementCounter() {
    count++;
    notifyListeners();
  }
}

2. Create a Widget using ViewModelFactory

Inject the ViewModelFactory into your widget to automatically handle ViewModel lifecycle:

import 'package:flutter/material.dart';
import 'package:inject_annotation/inject_annotation.dart';
import 'package:inject_flutter/inject_flutter.dart';
import 'home_page_view_model.dart';

@assistedFactory
abstract class HomePageFactory {
  HomePage create({Key? key, required String title});
}

class HomePage extends StatelessWidget {
  @assistedInject
  const HomePage({
    @assisted super.key,
    @assisted required this.title,
    required this.viewModelFactory,
  });

  final String title;
  final ViewModelFactory<HomePageViewModel> viewModelFactory;

  @override
  Widget build(BuildContext context) {
    return viewModelFactory(
      builder: (context, viewModel, _) {
        return Scaffold(
          appBar: AppBar(title: Text(title)),
          body: Center(
            child: Text('Count: ${viewModel.count}',
                style: Theme.of(context).textTheme.headlineMedium),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: viewModel.incrementCounter,
            child: const Icon(Icons.add),
          ),
        );
      },
    );
  }
}

3. Set up your Component

Create a component to tie everything together:

import 'package:flutter/material.dart';
import 'package:inject_annotation/inject_annotation.dart';
import 'home_page.dart';

import 'main.inject.dart' as g;

@component
abstract class AppComponent {
  static const create = g.AppComponent$Component.create;

  @inject
  HomePageFactory get homePageFactory;
}

void main() {
  final component = AppComponent.create();
  runApp(MyApp(homePageFactory: component.homePageFactory));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.homePageFactory});

  final HomePageFactory homePageFactory;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: homePageFactory.create(title: 'ViewModel Example'),
    );
  }
}

4. Generate the Code

Run the build_runner to generate the necessary code:

dart run build_runner build

How It Works

The ViewModelFactory automatically:

  1. Creates the ViewModel instance when the widget is initialized
  2. Listens for state changes and rebuilds the widget when needed
  3. Disposes the ViewModel when the widget is removed from the tree

This gives you clean separation of business logic from UI code without manual lifecycle management.

Complete Example

See the example folder for a complete working example of a counter app that demonstrates:

  • ViewModel injection and lifecycle management
  • Using factories for creating widgets with injected dependencies
  • Assisted injection for parameters provided at runtime
  • Proper component setup

Additional Information

  • Check the documentation for more details about inject.dart
  • Issues and feature requests can be filed on the GitHub issue tracker
  • Contributions are welcome! Please feel free to submit a Pull Request

Libraries

inject_flutter
A DI framework for Dart