ref.watch not watching over state change of a Provider function

71 Views Asked by At

I am using a Consumer to watch over state changes in an Object provided by Provider function but the ref.watch doesn't seem to rebuild the Consumer.

Application contains 2 pages: home_page and settings_page.

Providers: dbHelperInstanceProvider, sharedPreferencesProvider, maalaCompletedProvider provider functions for providing instances of classes DBHelper, SPHelper classes and other simple and necessary functionalities.
Major Providers being: currentMaalaManagerProvider and CurrentStateProvider providing instance of CurrentMaalaManager class to be as repository instance inside riverpod class CurrentStateProvider, which is used for showing data on home_page and triggering functions for changing states.

Below is the code I feel important to share to understand situation better:

CurrentMaalaManagerProvider function:

@riverpod
CurrentMaalaManager currentMaalaManager(CurrentMaalaManagerRef ref) {
  var db = ref.watch(dbHelperInstanceProvider);
  var sp = ref.watch(sharedPreferencesProvider);
  var compl = ref.watch(maalaCompletedProvider);
  return CurrentMaalaManager(db, sp, compl);
}

CurrentMaalaManager class:

class CurrentMaalaManager {
  final DBHelper _db;
  final SPHelper _sp;
  final MaalaCompleted completionStatus;
  int? _nextMaalaLengthOnRestart; // ATTRIBUTE WHOSE CHANGING VALUES ref.watch IS FAILING TO REACT TO 
  int? get nextMaalaLengthOnRestart => _nextMaalaLengthOnRestart;
  int? _lastClearedJaaps;
  CurrentMaalaManager(this._db, this._sp, this.completionStatus) {
    init();
  }
  void init() async {
    _nextMaalaLengthOnRestart = await _sp.getNextMaalaLengthOnRestart();
  }

 Future<CurrentMaalaData> setMaalaLength(
      int newLength,
      Future<bool?> Function() fromNextMaala,
      CurrentMaalaData currentMaalaObject) async {
    //...
    bool? fromNext = await fromNextMaala();
    if(fromNext==true){
       await _sp.setNextMaalaLengthOnRestart(newLength);
      _nextMaalaLengthOnRestart = newLength;
    }
    //...
   //returning CurrentMaalaData object for setting new state in CurrentStateProvider-> which will be used to trigger this function.
  }

 //...other functions (which also change value of member '_nextMaalaLengthOnRestart' ) here containing majority of other logic
}

CurrentStateProvider class:

@riverpod
class CurrentStateProvider extends _$CurrentStateProvider {
  @override
  FutureOr<CurrentMaalaData> build() async {
    var repo = ref.watch(currentMaalaManagerProvider);
    return await repo.loadLastSavedData();
  }
   Future<void> setMaalaLength(
      int newLength, Future<bool?> Function() fromNextMaala) async {
    var repo = ref.read(currentMaalaManagerProvider);

    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async => await repo.setMaalaLength(
        newLength, fromNextMaala, state.requireValue));
  }
  // ... other similar functions using currentMaalaManagerProvider as repo to make changes and setting new states.

}

A Consumer Widget inside home_page watching over providers:

Consumer(
            builder: (context, ref, child) {

              var display = ref.watch(currentStateProviderProvider);
              var completed = ref.watch(maalaCompletedProvider);

              return display.when(
                data: (data) {
                //...using data from watching over providers.
                  return Column(...);
                },
                error: (error, stackTrace) => Center(
                    child: Text("Error:\n $error\nStackTrace:\n$stackTrace")),
                loading: () => const CircularProgressIndicator(),
              );
          }
        )
      // An onTap function changing state:
     //onTap: () =>
    //       ref.read(currentStateProviderProvider.notifier).increment(),

A Consumer inside settings_page:

Consumer(
            builder: (context, ref, child) {
             // to get current state's maalaLength attribute
              var data = ref.watch(currentStateProviderProvider.select(
                  (value) => value.whenData((value) => value.maalaLength)));
            // to get CurrentMaalaManager instance's 'nextMaalaLengthOnRestart' attribute which is only managed inside class
            // and is not a part of state provided by above provider, whose value is being stored in data variable 
              var nextLen = ref.watch(currentMaalaManagerProvider
                  .select((value) => value.nextMaalaLengthOnRestart)); // SHOULD HAVE IDEALLY WATCHED OVER CHANGES BEING TRIGGERED ON BUTTON CLICK BELOW (according to me)
           
           return data.when(
                     data: (data){
                        return //..UI...
                            ElevatedButton(
                              onPressed: () async {
                               int newLen =
                                int.parse(lengthInputController.text);
                               // THE CALL TO .setMaalaLength BELOW CHNAGES THE VALUE OF attb _nextMaalaLengthOnRestart in CurrentMaalaManager class
                               // whose provider is also being watched above inside Consumer
                                    await ref
                                        .read(currentStateProviderProvider.notifier)
                                        .setMaalaLength(newLen, ()=> changeLengthFromCurrentOrNextMaala(context) // a dialog function asking for yes/no and providing Future<bool?> to function as parameter.
                                );
                               })
                              },
                              child: const Text("Set"),
                            ),

                     //....
                    nextLen!=null ? Text("$nextLen") : const SizedBox(height:5) // PROBLEM DISPLAYING THIS TEXT, EXPECTEDLY RIGHT WHEN NEW VALUE IS SET 
                
                        

Now the problem is that when the button right above is clicked, it runs the function .setMaalaLength which is also working fine but the Consumer is not reacting to the change in state of object of class CurrentMaalaManager whose attribute _nextMaalaLengthOnRestart is being changed by the triggered function which in turn according to me should have changed the value being returned by the concerned provider function leading to Consumer rebuild right when I press button to change values.

Instead what's happening is when I press the back button and go back to home_page, the concerned Consumer rebuilds and when i revisit the settings_page again, the Text("$nextLen") is visible which I expected to be getting visible right when the button was pressed.

I don't understand this strange behavior and have also tried making all the providers non-disposible by @Riverpod(keepAlive: true) annotation.

In my limited knowledge and experience with riverpod, I am unable to understand the cause of this problem and to fix my code. Kindly help me with the right approaches and reasons. Thank You

0

There are 0 best solutions below