Skip to content

Instantly share code, notes, and snippets.

@lukepighetti
Last active November 3, 2022 17:36
Show Gist options
  • Save lukepighetti/fd801d80ce4e9dd114fad670fae33aba to your computer and use it in GitHub Desktop.
Save lukepighetti/fd801d80ce4e9dd114fad670fae33aba to your computer and use it in GitHub Desktop.
import 'package:provider/provider.dart';
extension ProviderStoreBuildContextX on BuildContext {
/// Read the store once, doesn't subscribe a BuildContext to update.
AppStore readStore() => read<AppStore>();
/// Watch the store by subscribing to a BuildContext.
AppStore watchStore() => watch<AppStore>();
/// Select a piece of the store, subscribing a BuildContext to update only
/// when the underlying field changes. Uses `==` operator to determine changes
T selectField<T>(T Function(AppStore s) selector) => select(selector);
}
import 'package:flutter/foundation.dart';
/// A [ChangeNotifier] with built in fields for [initState], [initialized] and [setState].
///
/// Contains multiple [ChildStore]s
abstract class Store extends ChangeNotifier {
/// Initialize this store.
///
/// Must call super after initialization is complete.
@mustCallSuper
Future<void> initState() async {
_initialized = true;
notifyListeners();
}
/// If this [ChildStore] is fully initialized
bool get initialized => _initialized;
bool _initialized = false;
/// Alternative to notifyListeners. Matches [StatefulWidget] semantics.
void setState(Function fn) {
fn();
notifyListeners();
}
}
/// A [ChangeNotifier] with built in fields for [RootStore], [initState],
/// [initialized] and [setState].
abstract class ChildStore<T extends Store> extends Store {
ChildStore(this.store);
/// The parent store that contains this store.
final T store;
}
/// A [Store] that has a [registerStores]
/// method which connects these child stores to this [RootStore],
/// initializes them and then disposes of the subscription.
abstract class RootStore extends Store {
List<Store> _children = [];
/// Register stores with this [RootStore].
///
/// The root store will subscribe to all childrens
/// [notifyListeners] calls, initialize them, and dispose
/// of the subscription.
void registerChildren(List<Store> children) {
_children = children;
}
@override
Future<void> initState() async {
if (_children.isEmpty) {
debugPrint(
"WARNING: $this has no _children. Typically a RootStore would have _children stores.",
);
}
/// Connect the root store's [notifyListeners] method to
/// all child stores [notifyListeners] method.
for (var e in _children) {
e.addListener(notifyListeners);
}
/// Await all child store's [initState]
await Future.wait(_children.map((e) => e.initState()));
return super.initState();
}
@override
void dispose() {
/// Dispose all [notifyListeners] handlers.
for (var e in _children) {
e.removeListener(notifyListeners);
e.dispose();
}
super.dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment