async_redux
async_redux copied to clipboard
Debounce (protect against accidental multiple operations)
How to implement protection against too often heavy operations? For instance, if I pressed the "Save" button quickly several times. I don't want to save multiple times. I want to wait a 500 ms after last press and save only once.
In MobX we have a ready-made reaction 'delay' parameter (check the 101-105 lines): https://github.com/brianegan/flutter_architecture_samples/blob/master/mobx/lib/stores/todo_store.dart
In a pure Provider architecture I'd use an RxDart debounce() to control saving:
class Store with ChangeNotifier {
final _saveController = StreamController<item>(); //helper stream
final List<Item> _list = []; //data
Store() { _saveController.stream.debounce(ms: 500).listen => // do your save here }
void add(item) { //action
_list.add(item);
notifyListeners();
_saveController.add(item); //add event
}
}
But I have no idea, how to create similar functionality with Async Redux, because it's not recommended to keep streams in the store.
Please, first read this section of the documentation: https://pub.dev/packages/async_redux#progress-indicators
There are many ways to do that:
-
You can use the
Waitclass in the store to create a modal barrier (in the UI) to prevent the button from being tapped, or to turn off the button'sonTapcallback, while the save is being performed. -
Actions have an
abortDispatchmethod. You can use theWaitclass in the store to abort the dispatch while the save is being performed (or just returnnullfrom the reducer). -
You can add a
static bool isSavingfield to the action. Make ittruewhen the action starts (using the action'sbeforemethod), and make itfalsewhen it finishes (using the action'saftermethod). Then abort the dispatch if the bool is alreadytrue. Note theabortDispatchmethod runs before thebeforemethod. -
If you just want to have a time-based debouncing that cancels actions before some elapsed time, add a static
static DateTime lastfield to the action. Save the action'sstateTimestampto this variable when the action starts (using the action'sbeforemethod), and make itnullwhen it finishes (using the action'saftermethod). Then abort the dispatch if the action'sstateTimestampis not at leastxseconds from saved timestamp. -
However, if you want to have a time-based debouncing that groups actions within some elapsed time, it's a bit more complex. The store itself does this when it needs to call the state persistor. But it's also more complex because it checks not only the elapsed time, but also if the previous save has finished. I guess I could add some more functionality to the AsyncRedux's
Waitclass to allow for these more complex deboucings, but I'm not sure it's necessary. Usually I just prevent the button from being tapped during the save process, in the UI, using theWaitclass, and that's usually better than a time-based debouncing.
Usually I just prevent the button from being tapped during the save process, in the UI, using the Wait class, and that's usually better than a time-based debouncing.
It was just an example with button. I could move a slider back and forth and save after 2 seconds when I stopped. I cannot block UI in this case.
Yes, as I said, the store does that with the persistor. I will see if I can expose this functionality for general use.
For that purpose, I am using this library:
https://pub.dev/packages/easy_debounce
I am wrapping all dispatch() calls that I need to debounce with it.