skip to Main Content

I have a firebase snapshot StreamProvider

final poiChangesProvider = StreamProvider.autoDispose((ref) {
  return db.collection(POI.colPois)
           .withConverter<POI>(
             fromFirestore: (snapshot, _) => ...,
             toFirestore: (poi, _) => ...)
           .snapshots();
});

When I ref.watch/listen to it I get all the POIs and then a stream of changes, as expected.
But when I ref.watch it from multiple places, the first one to watch gets all the initial data, while all other watchers only receive the following updates.

How can I make a provider that caches and returns the last streamed data to new listeners?
The riverpod docs for StreamProvider state that it caches the latest value emitted by the stream, ensuring that if a listener is added after an event is emitted, the listener will still have immediate access to the most up-to-date event. But I have not been able to make this happen.

2

Answers


  1. You can build a provider that watches a stream, and slowly accumulates a snapshot. Something like:

    @riverpod
    myStream(ref) => SomethingMaking.aStream();
    
    @Riverpod(keepAlive: true)
    myValues(ref) {
      final values = [];
      ref.listen(myStreamProvider, (prev, cur) {
        values.add(cur);
        yield values;
      });
      return future; // start as loading until first emit
    }
    

    I may have gotten one thing or another wrong here… but the basic concept is you have an accumulator to hold all the values and emit the entire collection each tick.

    If you want to emit only the latest, but ensure prior values are also emitted on first contact, there are Stream extensions in package:async that can do that.

    Login or Signup to reply.
  2. StreamProvider keeping track of the last value and offering it to new listeners is the default behavior – assuming your listener is ref.watch.

    If you are talking about ref.listen, it has an optional fireImmediately parameter:

    // Inside providers
    ref.listen(
      provider,
      fireImmediately: true,
      (previous, next) => print('value $next'),
    );
    
    // Inside consumers
    ref.listenManual(
      provider,
      fireImmediately: true,
      (previous, next) => print('value $next'),
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search