# Dependency Injection

Manage your app's dependencies easily with built-in DI.

## What Is Dependency Injection?

Instead of creating objects directly, you register them and let the system provide them when needed.

```dart
// Instead of this
final service = MyService();

// Do this
i.addSingleton<MyService>((i) => MyService());
final service = Modular.get<MyService>();
```

## Quick Start

### 1. Register Dependencies

```dart
class HomeModule extends Module {
  @override
 FutureBinds binds(Injector i) {
    i.addSingleton<HomeController>((i)=> HomeController());
    i.add<ApiService>((i)=> ApiService());
  }
}
```

### 2. Use Dependencies

```dart
class HomePage extends StatefulWidget {
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  late final controller = context.read<HomeController>();
  //or
  final controller = Modular.get<HomeController>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(/* ... */);
  }
}
```

## Dependency Types

### Singleton
One instance for the entire app:

```dart
i.addSingleton<DatabaseService>((i) => DatabaseService());
```

### Factory
New instance every time:

```dart
i.add<ApiClient>((i) => ApiClient());
```

### Lazy Singleton
Created only when first used:

```dart
i.addLazySingleton<HeavyService>((i)=> HeavyService());
```

## Async Dependencies

For dependencies that need async initialization:

```dart
class DatabaseModule extends Module {
  @override
  FutureOr<void> binds(Injector i) async {
    // Wait for database connection
    await Future.delayed(Duration(seconds: 1));
    
    i.addSingleton<DatabaseService>((i)=> DatabaseService());
  }
}
```

## Using Keys

Register multiple instances of the same type:

```dart
// Register with keys
i.addSingleton<ApiService>((i) => ApiService(), key: 'main');
i.addSingleton<ApiService>((i) => ApiService(), key: 'backup');

// Use with keys
final mainApi = Modular.get<ApiService>(key: 'main');
final backupApi = Modular.get<ApiService>(key: 'backup');
```

## Context Extension

Use the convenient `context.read()` extension:

```dart
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final service = context.read<MyService>();
    return Text(service.getData());
  }
}
```

## Real Example

```dart
class ProductsModule extends Module {
  @override
 FutureBinds binds(Injector i) {
    i.addLazySingleton<ApiService>((i) => ApiService());
    i.add<ProductsRepository>((i) => ProductsRepository(api: i.get<ApiService>()));
    i.addSingleton<ProductsController>((i) => ProductsController(repository: i.get<ProductsRepository>()));
  }

  @override
  List<ModularRoute> get routes => [
    ChildRoute('/', child: (_, __) => ProductsPage()),
  ];
}

class ProductsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller = context.read<ProductsController>();
    return Scaffold(
      body: ...,
    );
  }
}
```

## Best Practices

1. **Register in modules** - Keep dependencies organized
2. **Use singletons for services** - Database, API clients
3. **Use factories for data** - Models, DTOs
4. **Use keys when needed** - Multiple instances of same type
5. **Keep modules focused** - One module, one feature

---

**Need more details?** Check out the [Key System](#key-system) section below.