flutter_architecture_samples icon indicating copy to clipboard operation
flutter_architecture_samples copied to clipboard

flutter_architecture_samples/firestore_redux/ how can I store the StreamSubscriptions?

Open SGuzel opened this issue 5 years ago • 6 comments

Hi Brian, I'm looking for a solution for storing streamsubscriptions in my middleware. How I can store the streamsubscription and cancel them if i need too?

Especially in flutter_architecture_samples/firestore_redux/lib/middleware/store_todos_middleware.dart line 66 / 67 there is a listen() which returns a subscription but it is not stored? How do you cancel the subscription?

In the E-Mail from Nilay couple days ago, there was a suggestion for using streamsubscriptions and canceling them.

http://dart-lang.github.io/linter/lints/cancel_subscriptions.html

class B {
  StreamSubscription _subscriptionB; 
  void init(Stream stream) {
    _subscriptionB = stream.listen((_) {});
  }
  void dispose(filename) {
    _subscriptionB.cancel();
  }
}

And I need in my code the fully control of the subscriptions. I would very appreciate your answer.

Cheers, :)

SGuzel avatar May 15 '19 07:05 SGuzel

Hey there :) There are a couple of techniques!

In that example, since we want to listen for the entire lifetime of the app, we don't bother with the subscription management as much. If you need to cancel a subscription in response to another Action coming in, I'd recommend using the redux_epics package! It's built to make middleware easier to use in a Stream-based way.

There's an example of cancelling a Stream in response to an action: https://github.com/brianegan/dart_redux_epics#cancellation

And a good blog post that describes some options as well (dispatching the correct "stop listening" action when the Widget that needs the stream of data from the backend is removed from the Widget tree): https://medium.com/shift-studio/flutter-redux-and-firebase-cloud-firestore-in-sync-2c1accabdac4

brianegan avatar May 17 '19 12:05 brianegan

Hi Brian, thanks for replying. I will have a deep dive into the solutions. :)

SGuzel avatar May 22 '19 07:05 SGuzel

I am also facing a similar issue in my codebase and I am trying the following:

As I start the subscription I dispatch an Action (SubscribedToStream) with the StreamSubscription object in it. This StreamSubscription is then stored in the AppState (appState.subscription)

When I want to stop it, I dispatch another Action (UnsubscribeFromStream), which then runs in the middleware appState.subscription.cancel.

Would this be a valid solution?

miquelbeltran avatar Jun 08 '19 20:06 miquelbeltran

@miquelbeltran I took a very similar approach some time ago that seemed to work when learning redux (wasn't familiar with epics or other approaches at the time).

I created a series of subscriptions to various parts of a Firebase backend and maintained the StreamSubscriptions in the AppState. Could cancel and create new subscriptions as required. Receiving async messages on each subscription worked fine. Remember to cancel any open subscriptions when exiting.

Works great for sharing state between multiple devices that have the same subscriptions (as used in messaging, etc...).

Since have moved on to a different arch so never used in production. Might want to get another take on this approach.

mmcc007 avatar Jun 08 '19 23:06 mmcc007

exactly my same use case, thanks @mmcc007 !

Remember to cancel any open subscriptions when exiting.

I have not thought about that, thanks for pointing out.

About other architectures, yes, I am actually thinking on using BLOC just for that specific use case while the rest of the app runs with Redux. Will see depending on how the solution works in production.

miquelbeltran avatar Jun 09 '19 09:06 miquelbeltran

I ended-up moving to bloc arch. The latest is provider arch. Both have been endorsed/promoted by Flutter Team (as well as redux). https://www.youtube.com/watch?v=d_m5csmrf7I&t=9s

mmcc007 avatar Jun 09 '19 16:06 mmcc007