useListenableSync<T, C extends Listenable> function

void useListenableSync<T, C extends Listenable>(
  1. Writable<T> node,
  2. C listenable, {
  3. required T getter(
    1. C listenable
    ),
  4. void setter(
    1. T value
    )?,
})

Subscribes to a Listenable and syncs it with a Writable node, optionally bidirectional.

Parameters:

  • node: The Writable node to sync with
  • listenable: The Listenable to subscribe to
  • getter: Function to get the value from the listenable
  • setter: Optional function to set the value to the listenable (enables bidirectional sync)

Example:

final signal = useSignal(0);
final notifier = ValueNotifier(0);
useListenableSync(
  signal,
  notifier,
  getter: (n) => n.value,
  setter: (value) => notifier.value = value, // Bidirectional sync
);

Implementation

void useListenableSync<T, C extends Listenable>(Writable<T> node, C listenable,
    {required T Function(C listenable) getter,
    void Function(T value)? setter}) {
  useMemoized(() {
    late final VoidCallback listener;
    late final VoidCallback disposer;

    if (setter != null) {
      bool skip = false;
      final watcher = Watcher(() => node.value, (value, __) {
        if (skip) {
          skip = false;
          return;
        }
        setter(value);
      }, when: IMutableCollection.skipNode(node));

      listener = () {
        skip = true;
        try {
          node.value = getter(listenable);
        } catch (_) {
          skip = false;
          rethrow;
        }
      };
      disposer = () {
        watcher.dispose();
        listenable.removeListener(listener);
      };
    } else {
      listener = () {
        node.value = getter(listenable);
      };
      disposer = () {
        listenable.removeListener(listener);
      };
    }

    listenable.addListener(listener);

    return disposer;
  }, (disposer) => disposer());
}