Closed shadyaziza closed 6 years ago
Hey hey -- it looks like there might be a couple of different issues tripping you up!
Stream<dynamic> ordersEpic(Stream<dynamic> actions, EpicStore<AppState> store)
is correct. Since an Epic
is defined this way: typedef Stream<dynamic> Epic<State>(Stream<dynamic> actions, EpicStore<State> store);
, and that's why you saw the initial type error. However, when you correctly tried to fix this, it appears Dart may be getting confused about the import of the AppState
class (that's why it kinda says AppState != AppState
). This can generally be solved by: moving the AppState
class into it's own file and importing it consistently with the full package-import: import 'package:my_app/app_state.dart';
in all files. Don't worry if this trips ya up -- It's literally the #1 support request I get across my libs, and I wish Dart was smarter about how it handles imports. This can happen if you create and use the AppState
class in your main.dart
file, and import it into other places, Dart will often run into trouble. Often times this means you have a circular dependency (define a class in main, import main.dart
in a reducer.dart
file, then import reducer.dart
in main.dart
).Stream<OrdersOnDataEventAction> actions
then trying to narrow this stream down to a Stream of RequestOrdersDataEventsAction
using the ofType
. Since RequestOrdersDataEventsAction
is not a subclass of OrdersOnDataEventAction
, you will never reach the switchMap
.I've copied / pasted your code into a new project, all in one main.dart
file and this code was working for me without type errors.
Hope this helps! Please let me know if you run into more trouble.
Note: I've created an AppState class + root reducer as I didn't see those above.
// State
class AppState {
final List<DocumentSnapshot> orders;
AppState({this.orders = const []});
}
// Epics
final allEpics = combineEpics<AppState>([ordersEpic]);
Stream<dynamic> ordersEpic(
Stream<dynamic> actions,
EpicStore<AppState> store,
) {
return Observable(actions)
.ofType(TypeToken<RequestOrdersDataEventsAction>())
.switchMap(
(RequestOrdersDataEventsAction requestOrders) => getOrders()
.map((orders) => OrdersOnDataEventAction(orders))
.takeUntil(actions
.where((action) => action is CancelOrdersDataEventsAction)));
}
Observable<List<DocumentSnapshot>> getOrders() {
return Observable(Firestore.instance.collection("orders").snapshots())
.map((QuerySnapshot q) => q.documents);
}
// Actions
class RequestOrdersDataEventsAction {}
class CancelOrdersDataEventsAction {}
class OrdersOnDataEventAction {
final orders;
OrdersOnDataEventAction(this.orders);
}
// Reducers
AppState stateReducer(AppState prev, dynamic action) {
return AppState(
orders: ordersReducer(prev.orders, action),
);
}
final ordersReducer = combineReducers<List<DocumentSnapshot>>([
TypedReducer<List<DocumentSnapshot>, OrdersOnDataEventAction>(_setOrders)
]);
List<DocumentSnapshot> _setOrders(
List<DocumentSnapshot> oldOrders,
OrdersOnDataEventAction action,
) {
return action.orders;
}
// Store
final store = Store<AppState>(
stateReducer,
initialState: AppState(orders: []),
middleware: [EpicMiddleware(allEpics)],
);
Thank you so much for the explanitation.
It was not working until I also changed the requestOrders
on switchMap
to a dynamic
type.
I have one more question to make sure I get this right. Now I am getting my list of orders to sync with what I have in the firestoer collection and I view it on a specific page, is there any down side that I am ALWAYS listening on this particular collection on this page, like performance issues. Am I handling this correctly, the desired outcome is that to fetch any updates happen on this collection in real time, is this way the correct one?
Hrm, that's odd -- using the ofType
method from Rx casts requestOrders
to a RequestOrdersDataEventsAction
for ya, so that should be accurate.
WRT the second question: If you only need to listen to that collection on a certain page, I'd recommend you start listening for Firestore Changes when the screen is initialized and stop listening when the screen is disposed. You could follow the instructions in this post for advice on how to do it: https://medium.com/shift-studio/flutter-redux-and-firebase-cloud-firestore-in-sync-2c1accabdac4
Yes I am using this method already
onInit: (store)=>store.dispatch( RequestOrdersDataEventsAction()),
onDispose: (store)=>store.dispatch( CancelOrdersDataEventsAction()),
And to be honest the application will have this one single screen displayed for a long time so I wanted to double check. Thanks again for the help and keep up the great work :)
Sure thing! I'll close this one out for now, but please feel free to file another issue if ya run into trouble
I am trying to sync my Firestore with Redux. I am using the following:
When I try to add my epics to the middleware I get this error on this line of code:
Epic:
Actions:
Orders:
Note I have also tried
Stream<dynamic> ordersEpic(Stream<dynamic> actions, EpicStore<AppState> store)
and I get the same error
The element type '(Stream<dynamic>, EpicStore<AppState>) → Stream<dynamic> can't be assigned to the list type '(Stream<dynamic>, EpicStore<AppState>) → Stream<dynamic>
This issue is also referenced on SO here