useMemoizedStream
Combines useMemoized and useStream: it memoizes the Stream returned by a factory and subscribes to it, re-subscribing only when keys change.
Widget buildOrders(BuildContext context, OrderService service, String userId) {
// Re-subscribes only when userId changes.
final snapshot = useMemoizedStream(
() => service.streamOrders(userId),
keys: [userId],
);
if (snapshot.hasError) return const Text('Could not load orders');
final orders = snapshot.data;
if (orders == null) return const Text('Loading...'); // <- null until the first event
return Text('${orders.length} orders');
}
Signature
AsyncSnapshot<T> useMemoizedStream<T>(
Stream<T>? Function() block, {
T? initialData,
bool preserveState = true,
HookKeys keys = hookKeysEmpty,
});
T? useMemoizedStreamData<T>(
Stream<T>? Function() block, {
T? initialData,
bool preserveState = true,
void Function(Object, StackTrace)? onError,
HookKeys keys = hookKeysEmpty,
});
block- factory that produces theStream. It runs on first build and again wheneverkeyschange. Returningnullmeans "no subscription yet" - the gate used to defer subscribing until a prerequisite is ready.keys- theuseMemoizedkeys. With the default empty list theblockruns exactly once.initialData,preserveState- forwarded touseStream; see useStream.
useMemoizedStreamData returns data directly and forwards onError to the built-in error handler.
Use cases
-
Subscribing to a backend stream parameterized by an argument, re-subscribing when that argument changes.
-
Backing a global state with a live stream. The snapshot's
connectionStatedoubles as an "initialized" signal once it reachesConnectionState.active:class OrdersState {final bool isInitialized;final List<Order>? orders;const OrdersState({required this.isInitialized, required this.orders});}OrdersState useOrdersState(OrderService service, String userId) {final snapshot = useMemoizedStream(() => service.streamOrders(userId), keys: [userId]);return OrdersState(// The stream is "connected and has emitted" once it reaches the active state.isInitialized: snapshot.connectionState == ConnectionState.active,orders: snapshot.data,);}
Caveats
-
Put every value the
blockreads intokeys, or theStreamwill not re-subscribe when that value changes - the same closure-capture caveat asuseMemoized. -
Like
useStream, this exposes only the latest value; intermediate events emitted between builds are lost. For per-event side effects useuseStreamSubscription.
See also
- useStream - the underlying hook and its
AsyncSnapshotsemantics - useMemoized - the caching half of this hook
- useStreamSubscription - handle every event rather than the latest value
- useMemoizedFuture - the same pattern for a one-shot
Future