linkedSignal<T, S> function

LinkedSignal<T, S> linkedSignal<T, S>(
  1. S source(), {
  2. LinkedSignalOptions<T, S>? options,
})

A highly powerful, mutable computed signal that derives its default value from an underlying source, but allows manual write overrides. Crucially, whenever the underlying source value changes, the signal automatically discards any local manual overrides and resets back to the newly computed default.

This hybrid behavior is the perfect solution for synchronizing local edit state with external remote state.

1. Real-World Use Case: Profile Form Editor

Imagine you are building a profile editor where the user can modify their username:

  • The initial/remote username is fetched from a database and held in a source signal.
  • The text input field is bound to a local signal.
  • The user should be able to edit the field locally (overriding the remote default).
  • If the selected user changes (e.g., they switch to a different profile in a list), the text field must automatically discard any local changes and reset to the new user's username.
// The remote/source state
final selectedUser = signal(User(id: 1, name: 'Alice'));

// The local editable state linked to the remote source
final username = linkedSignal(() => selectedUser.value.name);

print(username.value); // 'Alice'

// User edits the text field:
username.value = 'Bob';
print(username.value); // 'Bob' (local override active)

// Switch remote profile:
selectedUser.value = User(id: 2, name: 'Charlie');

// Local overrides are discarded and reset to the new source:
print(username.value); // 'Charlie'

2. Custom Computations using LinkedSignalOptions

By default, a linked signal directly passes the source value through. You can customize this mapping using a custom computation function that has access to both the current source value and the previous state:

final counter = signal(10);

final doubled = linkedSignal(
  () => counter.value,
  options: LinkedSignalOptions(
    computation: (sourceVal, prev) {
      print('Source changed to $sourceVal. Previous value was: ${prev?.value}');
      return sourceVal * 2;
    },
  ),
);

3. Custom Source Equality

To prevent unnecessary resets, you can supply a custom sourceEquality callback. The signal will only reset when the equality check returns false:

final selectedUser = signal(User(id: 1, name: 'Alice'));

final username = linkedSignal(
  () => selectedUser.value,
  options: LinkedSignalOptions(
    // Only reset when the user ID actually changes:
    sourceEquality: (a, b) => a.id == b.id,
  ),
);

Implementation

LinkedSignal<T, S> linkedSignal<T, S>(
  S Function() source, {
  LinkedSignalOptions<T, S>? options,
}) {
  return LinkedSignal<T, S>(
    source: source,
    options: options,
  );
}