computedStream<R, D> function

Result<R> computedStream<R, D>(
  1. R computation(), {
  2. bool notEqual = true,
})

Efficiently create a derived value from a computation.

computedStream provides a solution to efficiently use a value derived from a composition of signals. It returns a ValueStream whose value only gets updated when both its dependencies update and when the result of the computation is notEqual to the previous value of the ValueStream.

computedStream should be used to assist in minimizing running expensive computations and not as a way to magically optimize your codebase. In addition to prevent unnecessary UI updates, the value of ValueStream only updates when a computation's dependencies update and when the result of the computation is notEqual to the value of ValueStream.

This behaviour is enabled by default but it can be disabled by default by setting notEqual to false. This makes computedStream update the ValueStream regardless of the result of the computation.

Implementation

Result<R> computedStream<R, D>(R Function() computation,
    {bool notEqual = true}) {
  /// The cached values of the [dependencies].
  final (cached, setCached) = signal<Cache<D>>({});

  /// The signals that the [computation] is dependent on.
  final Dependencies<D> dependencies = {};

  /// Stream that encapsulates the resulting value.
  final stream = BehaviorSubject<R>();

  final (_, :push, :pull) = effects;

  push((dependency) {
    if (dependency is BehaviorSubject<D>) dependencies.add(dependency);

    // Record the current state of the dependencies...
    final Set<D> dependenciesState = {
      for (final dependency in dependencies) dependency.value
    };

    // ... and pass the state to the cache.
    setCached({...dependenciesState});

    // The effect.
    return () {
      final Set<D> dependenciesState = {
        for (final dependency in dependencies) dependency.value
      };

      if (cached() != dependenciesState) {
        final result = computation();

        if (!(notEqual && result == stream.value)) stream.add(result);

        setCached(dependenciesState);
      }
    };
  });

  stream.add(computation());
  pull();

  return stream.stream;
}