Search code examples
flutterflutter-dependenciesriverpodriverpod-annotation

How to pass dependency to AsyncNotifier with the new Riverpod syntax?


I'm currently using the new Riverpod syntax but I'm having an error and haven't been able to find a solution. I need to pass a dependency but it gives me this error The class TaskHomeInit must have a default constructor. Does anyone know another way to pass the HomeRepository dependency to it. When I don't place the constructor the error is that it needs to be initialized.

@Riverpod(keepAlive: true)
class TaskHomeInit extends _$TaskHomeInit {
  final HomeRepository homeRepository;
  // Constructor
  TaskHomeInit({required this.homeRepository}); // here is error
  @override
  Future<TasksHomeState> build() async {
    final List<TaskHome> taskHome = await homeRepository.getTaskHome();
    return TasksHomeState(isLoading: false, tasksHome: taskHome);
  }
}

When I don't create the constructor, I get this error: The final variable 'homeRepository' must be initialized. Try initializing the variable.

HomeRepository abstract class

abstract class HomeRepository {
  Future<List<TaskHome>> getTaskHome();
}

Implementation HomeRepository

class HomeRepositoryImpl extends HomeRepository {
  final HomeDatasource datasource;
  HomeRepositoryImpl(this.datasource);
  @override
  Future<List<TaskHome>> getTaskHome() async {
    final test =  await datasource.getTaskHome();
    return test;
  }
}


Solution

  • In riverpod world, dependency injection is usually done with the Ref object. Instead of injecting the dependency via constructor, create a provider.

    @Riverpod(keepAlive: true)
    HomeRepository homeRepo(HomeRepoRef ref) => HomeRepositoryImpl(ref.watch(homeDatasourceProvider);
    
    @Riverpod(keepAlive: true)
    HomeDatasource homeDatasource(HomeDatasourceRef ref) => HomeDatasourceImpl();
    

    Inside the Notifier/AsyncNotifier's build method, use ref.watch to access the dependency. It is safe and recommended to use ref.watch inside the build method.

    @override
    Future<TasksHomeState> build() async {
      final repo = ref.watch(homeRepoProvider);
      final taskHome = await repo.getTaskHome();
      return ...
    }