Search code examples
flutterriverpod

Flutter riverpod debounce multiple dependent providers


As described in the Riverpod docs, a Riverpod provider can watch other providers to make a "processing pipeline".

I have something like this:

final prov = Provider<String>((ref){

    final w1 = ref.watch(prov1);
    final w2 = ref.watch(prov2);
    final w3 = ref.watch(prov3);
    final w4 = ref.watch(prov4);

    final complex = expensiveFunction(w1,w2,w3,w4);

    return complex;
});

prov1 to prov4 can be modified individually by various bits of UI But some UI actions cause some or all of them to change in quick succession.

How can I debounce calls to expensiveFunction() until none of w1..w4 have changed for say 2 secs?


Solution

  • From this tweet of the author of the riverpod package, here is how you can do it:

    /// An extension on [Ref] with helpful methods to add a debounce.
    extension RefDebounceExtension on Ref {
      /// Delays an execution by a bit such that if a dependency changes multiple
      /// time rapidly, the rest of the code is only run once.
      Future<void> debounce(Duration duration) {
        final completer = Completer<void>();
        final timer = Timer(duration, () {
          if (!completer.isCompleted) completer.complete();
        });
        onDispose(() {
          timer.cancel();
          if (!completer.isCompleted) {
            completer.completeError(StateError('Cancelled'));
          }
        });
        return completer.future;
      }
    }
    
    final prov = FutureProvider<String>((ref) async {
    
        final w1 = ref.watch(prov1);
        final w2 = ref.watch(prov2);
        final w3 = ref.watch(prov3);
        final w4 = ref.watch(prov4);
        
        try {
          await debounce(Duration(seconds: 2));
        } on StateError {
          return;
        }
    
        final complex = expensiveFunction(w1,w2,w3,w4);
    
        return complex;
    });