mobxjs / mobx.dart

MobX for the Dart language. Hassle-free, reactive state-management for your Dart and Flutter apps.
https://mobx.netlify.app
MIT License
2.4k stars 310 forks source link

debounce / throttle reactions #774

Open subzero911 opened 2 years ago

subzero911 commented 2 years ago

As these methods are often used in most apps, I suggest to add them to MobX. This will save us from dealing with rx_dart.

// Called every time the user stops typing
Observable<String> obsText = Observable(textController.text);
debounce(obsText.value, (text) => search(text), time: Duration(milliseconds: 500));

/// Ignore all clicks within 1 second.
ObservableStream buttonClicks;
throttle(buttonClicks.value, (_) => Navigator.push(context, NextPage()), time: Duration(seconds: 1));

They are already present in GetX (but reactions with strange name "workers", and throttle is called "interval"): https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md#workers I'm not fond of GetX myself, but I found the idea of debounce and throttle reactions convenient.

deadsoul44 commented 2 years ago

There is a package for stream transformation from dart team. I am using it to throttle streams. https://pub.dev/packages/stream_transform

subzero911 commented 2 years ago

But this still requires including the side package. And it's for stream transformation, not for working with Observable type.

amondnet commented 2 years ago

@subzero911

https://mobx.netlify.app/examples/connectivity

reaction((_) => store.connectivityStream.value, (result) {
                final messenger = ScaffoldMessenger.of(context);

                messenger.showSnackBar(SnackBar(
                    content: Text(result == ConnectivityResult.none
                        ? 'You\'re offline'
                        : 'You\'re online')));
              }, delay: 4000);

A reaction is used here as we are only interested in letting users know when the connection state changes. The value passed as the first argument to the reaction function represents reactive state that needs to be tracked i.e. the status of the user's connection. The second argument represents the code that we want executed whenever the reactive state changes.

In this example, we want a snackbar displayed to notify users about updates to their connection status. In areas where connections can repeatedly drop in and out, it may be desirable to avoid showing too many messages that would otherwise degrade the user experience. To solve this problem, the reaction function allows specifying a delay in milliseconds. In this scenario, we have specified a delay of 4000 milliseconds (i.e. 4 seconds). The effect of this is that the snackbar will only be shown if 4 seconds have passed since the status of the user's connection has changed.

subzero911 commented 2 years ago

So the delay parameter is actually a debounce? Wow, I didn't know about it.

deadsoul44 commented 2 years ago

But this still requires including the side package. And it's for stream transformation, not for working with Observable type.

It also works with observables. You will just add .asObservable after stream transformation.

subzero911 commented 2 years ago

It makes sense to rename delay parameter to debounce, because it actually is.

jshji252 commented 3 months ago

This was a nice found, i didn't know such a thing as 'delay' existed as a part of API! Thanks for the discussion, people from the past!

One thing I may add to this thread is, the 'delay' is equivalent to 'throttle', not 'debounce' (of RX lingo). I just made a small example and tested, and it periodically emits events even if i continuously start a new event (for debouncing, it will only emit the very last event, after a period of inactivity).

I guess in many cases you can get away with 'delay' even when you want debouncing, but the differences are worth noting still!

reverberedechoes commented 2 months ago

@subzero911 I thought delay was actually a throttle.