From 56f9b0409ea6f20b81370d8399abe94a7cad4c17 Mon Sep 17 00:00:00 2001 From: gruvw Date: Mon, 23 Oct 2023 13:09:15 +0200 Subject: [PATCH 1/4] Add the useOnListenableChange hook (see https://github.com/rrousselGit/flutter_hooks/issues/389) --- README.md | 1 + packages/flutter_hooks/lib/src/listenable.dart | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/README.md b/README.md index 2eed934c..12ca1d66 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ They will take care of creating/updating/disposing an object. | [useListenableSelector](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useListenableSelector.html) | Similar to `useListenable`, but allows filtering UI rebuilds | | [useValueNotifier](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useValueNotifier.html) | Creates a `ValueNotifier` which will be automatically disposed. | | [useValueListenable](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useValueListenable.html) | Subscribes to a `ValueListenable` and return its value. | +| [useOnListenableChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnListenableChange.html) | Subscribes to a `Listenable` and registers `listener` to the passed `listenable`. | #### Misc hooks: diff --git a/packages/flutter_hooks/lib/src/listenable.dart b/packages/flutter_hooks/lib/src/listenable.dart index 1284f2dc..8313abcd 100644 --- a/packages/flutter_hooks/lib/src/listenable.dart +++ b/packages/flutter_hooks/lib/src/listenable.dart @@ -128,3 +128,15 @@ class _UseValueNotifierHookState @override String get debugLabel => 'useValueNotifier'; } + +/// Subscribes to a [Listenable] and registers `listener` to the passed `listenable`. +/// +/// See also: +/// * [useListenable] +void useOnListenableChange(void Function() listener, Listenable listenable) { + useEffect(() { + listenable.addListener(listener); + + return () => listenable.removeListener(listener); + }, listenable); +} From bf9d6cae8da0b6336f250d3457e7b1709c8754e3 Mon Sep 17 00:00:00 2001 From: gruvw Date: Mon, 23 Oct 2023 13:51:56 +0200 Subject: [PATCH 2/4] Converted to class syntax for useOnListenableChange --- .../flutter_hooks/lib/src/listenable.dart | 56 +++++++++++++++++-- .../test/use_on_listenable_change.dart | 1 + 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 packages/flutter_hooks/test/use_on_listenable_change.dart diff --git a/packages/flutter_hooks/lib/src/listenable.dart b/packages/flutter_hooks/lib/src/listenable.dart index 8313abcd..3dc2a13f 100644 --- a/packages/flutter_hooks/lib/src/listenable.dart +++ b/packages/flutter_hooks/lib/src/listenable.dart @@ -133,10 +133,56 @@ class _UseValueNotifierHookState /// /// See also: /// * [useListenable] -void useOnListenableChange(void Function() listener, Listenable listenable) { - useEffect(() { - listenable.addListener(listener); +/// * [useEffect] +void useOnListenableChange(VoidCallback listener, Listenable listenable) { + use(_OnListenableChangeHook(listener, listenable)); +} + +class _OnListenableChangeHook extends Hook { + _OnListenableChangeHook(this.listener, this.listenable) + : super(keys: [listenable]); + + final VoidCallback listener; + final Listenable listenable; + + @override + _OnListenableChangeHookState createState() => _OnListenableChangeHookState(); +} + +class _OnListenableChangeHookState + extends HookState { + Dispose? disposer; + + @override + void initHook() { + super.initHook(); + scheduleEffect(); + } + + @override + void didUpdateHook(_OnListenableChangeHook oldHook) { + super.didUpdateHook(oldHook); + + if (hook.keys == null) { + disposer?.call(); + scheduleEffect(); + } + } + + @override + void build(BuildContext context) {} - return () => listenable.removeListener(listener); - }, listenable); + @override + void dispose() => disposer?.call(); + + void scheduleEffect() { + hook.listenable.addListener(hook.listener); + disposer = () => hook.listenable.removeListener(hook.listener); + } + + @override + String get debugLabel => 'useOnListenableChange'; + + @override + bool get debugSkipValue => true; } diff --git a/packages/flutter_hooks/test/use_on_listenable_change.dart b/packages/flutter_hooks/test/use_on_listenable_change.dart new file mode 100644 index 00000000..70b786d1 --- /dev/null +++ b/packages/flutter_hooks/test/use_on_listenable_change.dart @@ -0,0 +1 @@ +// TODO From 99874135a05427b5a9f00436da5761ac88a6bac2 Mon Sep 17 00:00:00 2001 From: gruvw Date: Mon, 23 Oct 2023 13:57:30 +0200 Subject: [PATCH 3/4] Renamed with _test suffix --- ..._listenable_change.dart => use_on_listenable_change_test.dart} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/flutter_hooks/test/{use_on_listenable_change.dart => use_on_listenable_change_test.dart} (100%) diff --git a/packages/flutter_hooks/test/use_on_listenable_change.dart b/packages/flutter_hooks/test/use_on_listenable_change_test.dart similarity index 100% rename from packages/flutter_hooks/test/use_on_listenable_change.dart rename to packages/flutter_hooks/test/use_on_listenable_change_test.dart From 81d2dbb5d376873497345366ee85cc17009b1279 Mon Sep 17 00:00:00 2001 From: gruvw Date: Mon, 23 Oct 2023 14:08:05 +0200 Subject: [PATCH 4/4] Fixed class syntax comments --- packages/flutter_hooks/lib/src/listenable.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/flutter_hooks/lib/src/listenable.dart b/packages/flutter_hooks/lib/src/listenable.dart index 3dc2a13f..703e921d 100644 --- a/packages/flutter_hooks/lib/src/listenable.dart +++ b/packages/flutter_hooks/lib/src/listenable.dart @@ -139,8 +139,7 @@ void useOnListenableChange(VoidCallback listener, Listenable listenable) { } class _OnListenableChangeHook extends Hook { - _OnListenableChangeHook(this.listener, this.listenable) - : super(keys: [listenable]); + _OnListenableChangeHook(this.listener, this.listenable); final VoidCallback listener; final Listenable listenable; @@ -163,7 +162,7 @@ class _OnListenableChangeHookState void didUpdateHook(_OnListenableChangeHook oldHook) { super.didUpdateHook(oldHook); - if (hook.keys == null) { + if (hook.listenable != oldHook.listenable) { disposer?.call(); scheduleEffect(); } @@ -176,8 +175,10 @@ class _OnListenableChangeHookState void dispose() => disposer?.call(); void scheduleEffect() { - hook.listenable.addListener(hook.listener); - disposer = () => hook.listenable.removeListener(hook.listener); + void listener() => hook.listener(); + + hook.listenable.addListener(listener); + disposer = () => hook.listenable.removeListener(listener); } @override