skip to Main Content

I have a class called NavigatorRepository that I am trying to access, userProvider. How should I be accessing the userProvider inside the NavigatorRepository? I feel like i’ve tried everything, except the right thing…

Here is a snippet from NavigatorRepository

final user = Provider((ref) {
  return ref.watch(userProvider.notifier).getUser();
});
...

class NavigatorRepository {

...

  Future<dynamic> _get(
    String path, {
    Map<String, Object?>? queryParameters,
  }) async {
  
    var x = user; <== How do I get this to work?
}
 

}

UserProvider

class UserNotifier extends StateNotifier<User> {
  UserNotifier()
      : super(User(accessToken: '');

  void setUser(User user) {
    state = user;
  }

  User getUser() {
    return state;
  }
}


final userProvider = StateNotifierProvider<UserNotifier, User>((ref) {
  return UserNotifier();
});

2

Answers


  1. Chosen as BEST ANSWER

    Found this thread which covers what I am trying to do.

    https://github.com/rrousselGit/riverpod/issues/295#issuecomment-770384596


  2. There are many ways to do this.

    1. There is now a newer provider for this purpose, (Async)NotifierProvider:
    final navigatorProvider = NotifierProvider<NavigatorRepository, void>(() {
      return NavigatorRepository();
    });
    
    class NavigatorRepository extends Notifier<void> {
      
      @override
      void build() {
        // you can use ref.watch in this method
        User user = ref.watch(userProvider);
      }
    
      func() {
        // ref is available in any methods of the NavigatorRepository class
        ref.read(...);
      }
    
    1. The next method is to pass the ref parameter to the class constructor:
    final navigatorProvider = Provider<NavigatorRepository>(NavigatorRepository.new);
    
    
    class NavigatorRepository {
      NavigatorRepository(this._ref);
    
      final Ref _ref;
    
      func() {
        // ref is available in any methods of the NavigatorRepository class
        _ref.read(...);
      }
    }
    
    1. The following way better expresses the principle of implementing dependencies, but follows against the design patterns in Riverpod:
    final navigatorProvider = Provider<NavigatorRepository>((ref) {
      return NavigatorRepository(
        authService: ref.watch(AuthService),
        settingService: ref.watch(SettingService),
        userService: ref.watch(UserService),
      );
    });
    
    class NavigatorRepository {
      UserService({
        required AuthService authService,
        required SettingService settingService,
        required UserService userService,
      })  : _authService = authService,
            _settingService = settingService,
            _UserService = userService;
    
      final AuthService _authService;
      final SettingService _settingService;
      final UserService _userService;
    
      func() {
        // simply call the method
        User user = _userService.getUser();
      }
    }
    

    The idea is that you pass all necessary dependencies immediately to the constructor of your class. In the end, you know for sure that your class-service only depends on the services that are in the constructor.

    Note also that I have made all services private to avoid outside access. If you don’t need it, make the fields open.

    1. You can simply pass the ref parameter when calling any method:
    class NavigatorRepository {
      ...
    
      Future<dynamic> _get(
        Ref ref,
        String path, {
        Map<String, Object?>? queryParameters,
      }) async {
        var user = ref.read(userProvider);
      }
    }
    

    Although here you could pass User user as a parameter to the method and use it inside. But apparently there can be more such dependencies and then it is easier just to pass ref.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search