Atanas Nankinski
Atanas Nankinski

Reputation: 57

# Flutter/Riverpod - Is it possible to read() StateNotifier from another StateNotifier()

I am developing flutter app using Riverpod as state management and i reached a point where i want to implement Error handling. The way i plan it is due to having base widget for all the pages for that base widget to implement error handling provider from State Notofier:

class ErrorNotifier extends StateNotifier<ErrorModel>{
  ErrorNotifier() : super(ErrorModel(showError: false, exception: '', errorTitle: ''));

  void createException({
    required String exception,
    required String errorTitle
  }){
    state = state.update(showError: true, exception: exception, errorTitle: errorTitle);
  }

  void disbandError() {
    state = state.update(showError: false);
  }
}

class ErrorModel {
  bool showError;
  String exception;
  String errorTitle;

  ErrorModel({
    required this.showError,
    required this.exception,
    required this.errorTitle,
  });

  ErrorModel update({bool? showError, String? exception, String? errorTitle}) {
    return ErrorModel(
      showError: showError ?? this.showError,
      exception: exception ?? this.exception,
      errorTitle: errorTitle ?? this.errorTitle,
    );
  }
}

final errorProvider = StateNotifierProvider<ErrorNotifier, ErrorModel>(
        (ref) => ErrorNotifier(),
);

So whenever the showError changes to true i want to display modal windwow from the base widget thus making the error handling global to all pages using the base widget, but i need to change the data to the error model via the other StateNotifiers. For example in this StateNotifier:

class OnboardingNotifier extends StateNotifier<bool> {
  OnboardingNotifier() : super(SharedPreferencesService().getOnboarding());

  void getOnboarding() {
    state = SharedPreferencesService().getOnboarding();
  }

  Future<void> setOnboarding(bool onboarding) async {
    await SharedPreferencesService().setOnboarding(onboarding);
  }
}

I want to add try and catch blocks in every method and whenever i catch error to read the ErrorHandlin provider and change the showError value to true and be watched from the base widget. I imagined something like that:

void getOnboarding() {
  state = SharedPreferencesService().getOnboarding();
  try {
    state = SharedPreferencesService().getOnboarding();
  } catch(e){
    ref.read(errorProvider.notifier).update(showError: true, exception: e, errorTitle: "Error occured")
  }
}

Future<void> setOnboarding(bool onboarding) async {
  try {
    await SharedPreferencesService().setOnboarding(onboarding);
  } catch(e){
    ref.read(errorProvider.notifier).update(showError: true, exception: e, errorTitle: "Error occured")
  }
}

I tried looking for possible solution but couldn't find similar questions nor anything in the documentation. I need to use the ErrorHandler provider in other StateNotifiers aswell and not just this one example.I would be very glad to haer someone did something like that or has better global error handling architecture.

Upvotes: 1

Views: 789

Answers (1)

Ruble
Ruble

Reputation: 4844

Starting with Riverpod 2.0 there is a new notifier - AsyncNotifierProvider and NotifierProvider. An instance of Ref ref will be available in all places in the class when extended from this provider.

A quick solution to your problem would be to pass ref as a class field:

class OnboardingNotifier extends StateNotifier<bool> {
  OnboardingNotifier(this._ref) : super(SharedPreferencesService().getOnboarding());

  final Ref _ref;

  void getOnboarding() {
    state = SharedPreferencesService().getOnboarding();
    try {
      state = SharedPreferencesService().getOnboarding();
    } catch(e){
      _ref.read(errorProvider.notifier).update(showError: true, exception: e, 
  errorTitle: "Error occured")
  }
}

}

And your provider will look like this:

final onboardingNotifier = StateNotifierProvider<OnboardingNotifier, bool>(
        (ref) => OnboardingNotifier(ref),
);

// or use tear-off

final onboardingNotifier = StateNotifierProvider<OnboardingNotifier, bool>(
        OnboardingNotifier.new
);

Upvotes: 0

Related Questions