Search code examples
flutterriverpodstream-provider

Nested Flutter Riverpod stream provider is firing twice on update


The stream below is expected to update every time the filter changes. But the attached listener is firing twice, once with the old values and again with the new values without an indication of which is which.

I have confirmed that tourFilterPovider is firing once only so the problem seems to be in the definition of the filteredOrderStream.

How can I change that to fire only with the new filtered list?

The stream provider:

@riverpod
Stream<List<Order>> filteredOrdersStream(FilteredOrdersStreamRef ref) {
  final repository = ref.watch(ordersRepositoryProvider);
  final filter = ref.watch(tourFilterProvider);
  if (filter.isEmpty) {
    return repository.watchOrders();
  } else {
    return repository.watchOrders().map((orders) {
      return orders.where((order) => filter.contains(order.tour)).toList();
    });
  }
}

@Riverpod(keepAlive: true)
OrdersRepository ordersRepository(OrdersRepositoryRef ref) {
  return OrdersRepository(FirebaseFirestore.instance);
}

class OrdersRepository {
...
  Stream<List<Order>> watchOrders() => queryOrders()
      .orderBy(Order.CREATEDAT_KEY, descending: true)
      .snapshots()
      .map((snapshot) => snapshot.docs.map((doc) => doc.data()).toList());
}

The consumer:

    ref.listen<AsyncValue>(filteredOrdersStreamProvider, (_, state) async {
      if (state.hasValue) {
        // PROBLEM: this is called with old and new values on every filter change
        final filteredOrders = state.value;
        // do something
      }
    });

Solution

  • The problem was not in the provider but in my listener.

    state.hasValue does not mean that the state is finished loading. The documentation says so much. This means that my listener was firing once with the old value during loading and a second time with the new value after loading was finished.

    Changing the check in my listener to if (!state.isLoading && state.hasValue) solved the issue.