Skip to content

Instantly share code, notes, and snippets.

@brianegan
Created November 16, 2018 13:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianegan/ad83f7bc2ce63976145596ab8cb51f7b to your computer and use it in GitHub Desktop.
Save brianegan/ad83f7bc2ce63976145596ab8cb51f7b to your computer and use it in GitHub Desktop.
ComputedValueNotifier concept
import 'package:flutter/foundation.dart';
/// A class that can be used to derive a value based on data from another
/// Listenable or Listenables.
///
/// The value will be recomputed when the provided [listenable] notifies the
/// listeners that values have changed.
///
/// ### Simple Example
///
/// ```dart
/// final email = ValueNotifier<String>('a');
///
/// // Determine whether or not the email is valid using a (hacky) validator.
/// final emailValid = ComputedValueNotifier(
/// email,
/// () => email.value.contains('@'),
/// );
///
/// // The function provided to ComputedValueNotifier is immediately executed,
/// // and the computed value is available synchronously.
/// print(emailValid); // prints 'false'.
///
/// // When the email ValueNotifier is changed, the function will be run again!
/// email.value = 'a@b.com';
/// print(emailValid); // prints 'true'.
/// ```
///
/// ### Deriving data from multiple listenables
///
/// In this case, we can use the `Lisetenable.merge` function provided by
/// Flutter to merge several variables.
///
/// ```dart
/// final email = ValueNotifier<String>('');
/// final password = ValueNotifier<String>('');
///
/// // Determine whether the email is valid, and make that a Listenable!
/// final emailValid = ComputedValueNotifier<bool>(
/// email,
/// () => email.value.contains('@'),
/// );
///
/// // Determine whether the password is valid, and make that a Listenable!
/// final passwordValid = ComputedValueNotifier<bool>(
/// password,
/// () => password.value.length >= 6,
/// );
///
/// // Now, we will only enable the "Login Button" when the email and
/// // password are valid. To do so, we can listen to the emailValid and
/// // passwordValid ComputedValueNotifiers.
/// final loginButtonEnabled = ComputedValueNotifier<bool>(
/// Listenable.merge([emailValid, passwordValid]),
/// () => emailValid.value && passwordValid.value,
/// );
///
/// // Update the email
/// print(emailValid.value); // false
/// print(loginButtonEnabled.value); // false
/// email.value = 'a@b.com';
/// print(emailValid.value); // true
/// print(loginButtonEnabled.value); // false
///
/// // Update the password
/// print(passwordValid.value); // false
/// password.value = '123456';
/// print(passwordValid.value); // true
/// print(loginButtonEnabled.value); // true
/// ```
class ComputedValueNotifier<T> extends ChangeNotifier
implements ValueListenable {
final Listenable listenable;
final T Function() compute;
T value;
ComputedValueNotifier(this.listenable, this.compute) {
_updateValue();
listenable.addListener(_updateValue);
}
@override
void dispose() {
listenable.removeListener(_updateValue);
super.dispose();
}
void _updateValue() {
value = compute();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment