effect function

EffectCleanup effect(
  1. EffectCallback compute, {
  2. String? debugLabel,
})

The effect function is the last piece that makes everything reactive. When you access a signal inside its callback function, that signal and every dependency of said signal will be activated and subscribed to. In that regard it is very similar to computed. By default all updates are lazy, so nothing will update until you access a signal inside effect.

import 'package:signals/signals.dart';

final name = signal("Jane");
final surname = signal("Doe");
final fullName = computed(() => name.value + " " + surname.value);

// Logs: "Jane Doe"
effect(() => print(fullName.value));

// Updating one of its dependencies will automatically trigger
// the effect above, and will print "John Doe" to the console.
name.value = "John";

You can destroy an effect and unsubscribe from all signals it was subscribed to, by calling the returned function.

import 'package:signals/signals.dart';

final name = signal("Jane");
final surname = signal("Doe");
final fullName = computed(() => name.value + " " + surname.value);

// Logs: "Jane Doe"
final dispose = effect(() => print(fullName.value));

// Destroy effect and subscriptions
dispose();

// Update does nothing, because no one is subscribed anymore.
// Even the computed `fullName` signal won't change, because it knows
// that no one listens to it.
surname.value = "Doe 2";

Implementation

EffectCleanup effect(EffectCallback compute, {String? debugLabel}) {
  final effect = _Effect(compute, debugLabel: debugLabel);
  try {
    effect._callback();
  } catch (e) {
    effect._dispose();
    _onEffectRemoved(effect);
    rethrow;
  }
  // Return a bound function instead of a wrapper like `() => effect._dispose()`,
  // because bound functions seem to be just as fast and take up a lot less memory.
  return () {
    effect._dispose();
    _onEffectRemoved(effect);
  };
}