Skip to content

Instantly share code, notes, and snippets.

@theniceboy
Last active October 31, 2023 01:38
Show Gist options
  • Save theniceboy/fa1546517f1b18faf3186a31c8f452c6 to your computer and use it in GitHub Desktop.
Save theniceboy/fa1546517f1b18faf3186a31c8f452c6 to your computer and use it in GitHub Desktop.
Simple stream-based state management in Flutter/Dart
import 'dart:async';
import 'package:async/async.dart';
import 'package:flutter/widgets.dart';
/*
This class is a little bit different than the [ValueNotifier] class:
- Setting the value ALWAYS notifies listeners, even if the value is the same.
- It uses streams over [ValueListenableBuilder]'s setState approach to make it
easier to use with other async code.
*/
class Observable<T> {
T _value;
T get value => _value;
set value(T v) {
_value = v;
_controller.add(v);
}
void notify() {
_controller.add(_value);
}
void setIfChanged(T v) {
if (v != _value) {
value = v;
}
}
Observable(this._value);
final _controller = StreamController<T>.broadcast();
Stream<T> get stream => _controller.stream;
}
class Observer<T> extends StatelessWidget {
final Observable<T> observable;
final Widget Function(BuildContext, T) builder;
const Observer({required this.observable, required this.builder, Key? key}) : super(key: key);
@override
Widget build(context) {
return StreamBuilder<T>(
stream: observable.stream,
builder: (context, value) {
return builder(context, observable.value);
},
);
}
}
class MultiObserver extends StatelessWidget {
final List<Observable> observables;
final Widget Function(BuildContext, List) builder;
const MultiObserver({required this.observables, required this.builder, Key? key})
: super(key: key);
@override
Widget build(context) {
return StreamBuilder(
stream: StreamGroup.merge(observables.map((o) => o.stream)),
builder: (context, value) {
return builder(context, observables.map((o) => o.value).toList());
},
);
}
}
/// A simplified [Observable] with "no" values
class Notifier extends Observable<bool> {
Notifier() : super(true);
}
class NotifierBuilder extends StatelessWidget {
final Notifier notifier;
final Widget Function(BuildContext) builder;
const NotifierBuilder({required this.notifier, required this.builder, Key? key})
: super(key: key);
@override
Widget build(context) {
return StreamBuilder(
stream: notifier.stream,
builder: (context, _) {
return builder(context);
},
);
}
}
@2qp
Copy link

2qp commented Oct 10, 2022

Thank you so much for this. means a lot @theniceboy 😳 💚

@theniceboy
Copy link
Author

No problem! @yuxcat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment