useValueListenableToSignal<T> function

ReadonlySignal<T> useValueListenableToSignal<T>(
  1. ValueListenable<T> value, {
  2. List<Object?> keys = const <Object>[],
  3. SignalOptions<T>? options,
})

Creates a new ReadonlySignal from a ValueListenable and subscribes to it.

This provides read-only interoperability with standard Flutter classes, allowing you to bridge any ValueListenable (like ScrollController, TextEditingController, or other custom listenables) into a reactive ReadonlySignal.

:::tip Perfect for listening to UI framework states such as scroll offsets, keyboard visibility, or text inputs in a clean, functional reactive style. :::

Parameters

  • value: The ValueListenable to bridge.
  • keys: A list of objects to watch. If any key changes, the signal is re-created.
  • debugLabel: An optional debug label.

Example

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:signals_hooks/signals_hooks.dart';

class ScrollTrackerWidget extends HookWidget {
  const ScrollTrackerWidget({super.key});

  @override
  Widget build(BuildContext context) {
    final scrollController = useScrollController();
    // Bridge the listenable offset to a reactive ReadonlySignal
    final scrollSignal = useValueListenableToSignal(scrollController);

    return Scaffold(
      appBar: AppBar(
        title: Text('Scroll Position: ${scrollSignal.value.toStringAsFixed(1)}'),
      ),
      body: ListView.builder(
        controller: scrollController,
        itemCount: 100,
        itemBuilder: (context, idx) => ListTile(title: Text('Row $idx')),
      ),
    );
  }
}

Implementation

ReadonlySignal<T> useValueListenableToSignal<T>(
  ValueListenable<T> value, {
  List<Object?> keys = const <Object>[],
  SignalOptions<T>? options,
}) {
  final s = useMemoized(
    () => valueListenableToSignal(
      value,
      debugLabel: options?.name,
      autoDispose: options?.autoDispose ?? false,
    ),
    keys,
  );
  return useExistingSignal(s, keys: keys);
}