Skip to content

Commit

Permalink
Add useOnStreamChange hook (#373)
Browse files Browse the repository at this point in the history
  • Loading branch information
jezsung authored Jul 21, 2023
1 parent 4f70845 commit 69e419a
Show file tree
Hide file tree
Showing 3 changed files with 389 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ They will take care of creating/updating/disposing an object.
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [useStream](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useStream.html) | Subscribes to a `Stream` and returns its current state as an `AsyncSnapshot`. |
| [useStreamController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useStreamController.html) | Creates a `StreamController` which will automatically be disposed. |
| [useOnStreamChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnStreamChange.html) | Subscribes to a `Stream`, registers handlers, and returns the `StreamSubscription`.
| [useFuture](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFuture.html) | Subscribes to a `Future` and returns its current state as an `AsyncSnapshot`. |

#### Animation related hooks:
Expand Down
95 changes: 95 additions & 0 deletions packages/flutter_hooks/lib/src/async.dart
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,98 @@ class _StreamControllerHookState<T>
@override
String get debugLabel => 'useStreamController';
}

/// Subscribes to a [Stream] and calls the [Stream.listen] to register the [onData],
/// [onError], and [onDone].
///
/// Returns the [StreamSubscription] returned by the [Stream.listen].
///
/// See also:
/// * [Stream], the object listened.
/// * [Stream.listen], calls the provided handlers.
StreamSubscription<T>? useOnStreamChange<T>(
Stream<T>? stream, {
void Function(T event)? onData,
void Function(Object error, StackTrace stackTrace)? onError,
void Function()? onDone,
bool? cancelOnError,
}) {
return use<StreamSubscription<T>?>(
_OnStreamChangeHook<T>(
stream,
onData: onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
),
);
}

class _OnStreamChangeHook<T> extends Hook<StreamSubscription<T>?> {
const _OnStreamChangeHook(
this.stream, {
this.onData,
this.onError,
this.onDone,
this.cancelOnError,
});

final Stream<T>? stream;
final void Function(T event)? onData;
final void Function(Object error, StackTrace stackTrace)? onError;
final void Function()? onDone;
final bool? cancelOnError;

@override
_StreamListenerHookState<T> createState() => _StreamListenerHookState<T>();
}

class _StreamListenerHookState<T>
extends HookState<StreamSubscription<T>?, _OnStreamChangeHook<T>> {
StreamSubscription<T>? _subscription;

@override
void initHook() {
super.initHook();
_subscribe();
}

@override
void didUpdateHook(_OnStreamChangeHook<T> oldWidget) {
super.didUpdateHook(oldWidget);
if (oldWidget.stream != hook.stream ||
oldWidget.cancelOnError != hook.cancelOnError) {
_unsubscribe();
_subscribe();
}
}

@override
void dispose() {
_unsubscribe();
}

void _subscribe() {
final stream = hook.stream;
if (stream != null) {
_subscription = stream.listen(
hook.onData,
onError: hook.onError,
onDone: hook.onDone,
cancelOnError: hook.cancelOnError,
);
}
}

void _unsubscribe() {
_subscription?.cancel();
}

@override
StreamSubscription<T>? build(BuildContext context) {
return _subscription;
}

@override
String get debugLabel => 'useOnStreamChange';
}
Loading

0 comments on commit 69e419a

Please sign in to comment.