useListenableListener
Runs a callback when a Listenable notifies, without rebuilding the hook. This is the
side-effect counterpart to useListenable: use it when a change should
trigger an action (logging, navigation, a snackbar) rather than new UI.
void useScrollToTopOnReachingEnd(ScrollController controller) {
// A ScrollController is a plain Listenable - it carries no single value, so
// the callback reads what it needs from the controller itself. No rebuild.
useListenableListener(controller, () {
if (controller.offset >= controller.position.maxScrollExtent) {
controller.jumpTo(0); // <- Side effect only; the hook never rebuilds
}
});
}
Signature
void useListenableListener(Listenable? listenable, void Function() block);
The listenable is nullable - passing null subscribes to nothing. The callback takes no
arguments, so read whatever you need from the listenable inside it. The subscription is
re-created when the listenable reference changes.
Use cases
- Reacting to a
Listenablethat carries no single value (aScrollController,TabController, a customChangeNotifier). - Side effects on change - showing a snackbar, logging analytics, triggering navigation - where no rebuild is wanted.
Caveats
- The callback does not cause a rebuild. If you need the new value on screen, use
useListenable(oruseValueListenable) instead. - Do not run the side effect during build - that is exactly what this hook avoids. Notifications arrive after the build, like an effect.
useValueListenableListener
The value-carrying variant for Flutter's ValueListenable<T>. The callback receives the current
value, so you do not read it off the source yourself.
void useLogTabChanges(ValueListenable<int> selectedTab) {
// useValueListenableListener passes the current value to the callback.
useValueListenableListener(selectedTab, (index) {
debugPrint('Tab changed to $index'); // <- Runs on every change, no rebuild
});
}
void useLogNameChanges(ListenableValue<String> name) {
// useListenableValueListener is the same, for utopia's ListenableValue
// (e.g. a useState result).
useListenableValueListener(name, (value) {
debugPrint('Name is now $value');
});
}
Signature
void useValueListenableListener<T>(ValueListenable<T>? listenable, void Function(T) block);
Calls block with the listenable's current value on every notification. The source is nullable
(null = no subscription); the subscription is re-created when the reference changes.
Use cases
- Logging or analytics on each value change, with the value passed straight to the callback.
- Driving a one-off effect (a dialog, navigation, a focus change) off a
ValueNotifier<T>or any FlutterValueListenable<T>without rendering the value itself.
Caveats
- The callback never rebuilds the hook. When the value needs to appear on screen, reach for
useValueListenableinstead. - Reach for this when you already hold a Flutter
ValueListenable<T>. For utopia'sListenableValue<T>(auseStateresult, auseNotifiableValue), useuseListenableValueListenerbelow instead of converting.
useListenableValueListener
The same as useValueListenableListener, but for utopia's ListenableValue<T> instead of
Flutter's ValueListenable<T>. Because a useState(...) result is a ListenableValue, this is
how you react to another hook's state without rebuilding on it.
Signature
void useListenableValueListener<T>(ListenableValue<T>? listenable, void Function(T) block);
Identical behavior to useValueListenableListener: block receives the current value, the
source is nullable, and the subscription tracks the reference.
Three sources, three hooks: useListenableListener for a bare Listenable,
useValueListenableListener for a Flutter ValueListenable, useListenableValueListener for a
utopia ListenableValue. Pick the one whose type you already hold rather than converting.
Use cases
- Logging or analytics on each value change.
- Driving a one-off effect (dialog, navigation, focus change) in response to a value, without the value itself being rendered.
Caveats
- These never rebuild the hook. Reach for
useValueListenable/useListenableValuewhen the value needs to appear in the UI.
See also
- useListenable - subscribe and rebuild on change instead of running an effect
- useNotifiable - the producing side: trigger notifications yourself
- Common hooks -
useEffectand the rest of the everyday hooks