DevelJoe
DevelJoe

Reputation: 1332

Use `state` within Riverpod Notifier build() method

I have a Flutter Notifier MyClassProvider whose value is an instance of a class, e.g.:

class MyClass {

  String propertyA;
  String propertyB;
  String propertyC;

}

The Notifier's instance propertyA value is dependent on a different provider otherProvider, while the other properties propertyB and propertyC are both independent from it.

So first, I tended to:

A) Use the previous state of the notifier in its build() method to only ever adapt the value of propertyA within its build() method, and take up the previous property values for propertyB and propertyC from that state, e.g. like:

--------------
Notifier file ('MyClassProvider'):
--------------
.
.
.
/// 'async' because the build() method of the 'otherProvider' is async
Future<MyClass> build() async {

  final otherProvidersValue = await ref.watch(otherProvider.future);

  final newAValue = await computeNewAValueFromOtherProviderValue(otherProvidersValue);

  /// Calculate value of `propertyA` based on value of 'otherProvider' & leave 
  /// rest untouched
  return MyClass(
     propertyA: newAValue, 
     propertyB: state.value != null ? state.value!.propertyB : 'defaultB', 
     propertyC: state.value != null ? state.value!.propertyC : 'defaultC',
  );

}
.
.
.

But then I came across the section of the riverpod docs saying:

DON'T perform side effects during the initialization of a provider

Although I don't consider the build() method of otherProvider to be a side-effect (it simply corresponds to an asynchronous data fetch, which can in turn however be triggered by other operations in the application), I looked for the following workaround, also because the fact that the providers' build() method is asynchronous due to its direct dependency from otherProvider is somewhat of a pain:

B) Leave the notifiers' build() method to be synchronous and code its dependency using ref.listen(otherProvider) and a callback executing the desired operation at the app root level, e.g.:

--------------
Notifier file ('MyClassProvider'):
--------------

.
.
.
/// no longer 'async' because dependency of the 'otherProvider' is managed outside notifer
MyClass build() {

  return MyClass(
     propertyA: 'defaultA', 
     propertyB: 'defaultB', 
     propertyC: 'defaultC',
  );

}
.
.
.

--------------
Apps Root Widget file:
--------------
.
.
.
build() {

ref.listen(otherProvider, (_, newValue) {
      newValue.when(
        data: (newlyProvidedValue) async {

         
          final newValueA = await computeNewAValueFromOtherProviderValue(newlyProvidedValue);

          /// Update Notifiers' State according to the new value of 'otherProvider'
          ref
            .read(MyClassProvider().notifier)
            .updatePropertyA(
              updatedValue: newValueA,
            );
          }
        },
        error: (error, traceStack) {
          /// Handle Error
        },
        loading: () {
          /// Handle Loading Animation
        },
      );
    });

.
.
}
.
.
.
.

I now wonder if there's any technical problem with the approach I use in B), and if so, if it is even "permitted" to use the state in the build() method of a provider as I do in A) ?

My application never crashed for either, but my experience with Flutter + State Management with Riverpod is limited, so I wanted to double-check.

Upvotes: 0

Views: 261

Answers (0)

Related Questions