Closed AdamBrodzinski closed 9 years ago
@AdamBrodzinski e..., it's easier to understand, but catch a error, but Interesting ^_^
Exception in queued task: Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.
the error inferred to a issue, maybe my guess:
dep.autorun run computation block after mini-mongo changed, BUT, Collection.observe invoke callbacks before mini-mongo changed.
I have looked up the official document, but it doesn't give a clear noticement.
I use follow code to test:
if (Meteor.isClient) {
Players.find({}).observe({
changed(docs) {
console.log('\n[observeChanges]');
console.log(docs);
// follow code will cause error: Cannot dispatch in the middle of a dispatch.
//CollectionActions.playersChanged(Player.findLeaders());
},
});
// watch collections on Minimongo cache and trigger action on change
Meteor.startup(() => {
Tracker.autorun(computation => {
var docs = Player.findLeaders(); //Players.find({}).fetch();
if (computation.firstRun) return; // ignore first empty run
console.log('\n[Tracker] collection changed');
this.CollectionActions.playersChanged(docs);
});
});
}
after select one play, and click 'Add 5 Points' bottom, the console is:
[PlayerActions] INCREMENT_SCORE K69oYBbmDokx9WnNb
[observeChanges]
Object {name: "Ada Lovelace", score: 55, _id: "K69oYBbmDokx9WnNb"}
[PlayerStore] incrementScore
[App] rendering
[Tracker] collection changed
[CollectionActions] PLAYERS_CHANGED [Object, Object, Object, Object, Object, Object]
[PlayerStore] updating state
[App] rendering
// in PlayStore
onIncrementScore(docId) {
//Player.incrementScore() could use a fat model also
Players.update({_id: docId}, {$inc: {score: 5}});
// no setState required since tracker will fire a change
console.log('[PlayerStore] incrementScore');
}
Execution order like this: PlayerActions.incrementScore --> dispatch to PlayerStore.onIncrementScore --> update mini-mongo(insecure mode cause sync server mongo data) --> trigger mongo observer(dispatch not end can't create another dispatch) --> now console in PlayStore.onIncrementScore dispatch end --> Track.autoRun --> ......
it's amaze when PlayStore.onIncrementScore update the mongo, the console statement follow update statement doesn't executed until cursor observer finished. seem like cousor observer has a higher priority. And if we invoke CollectionActions.playersChanged(Player.findLeaders())
in observe, the playersChanged action will be trigger with a new dispatch and cause error above. But Track.autoRun doesn't cause the error. I think it's because the dispatch created by PlayerActions.incrementScore has finished, and we can dispatch again.
omg, writing make me crazy, wish those words not crazy you, @AdamBrodzinski. Hope to have more discuss about this question.
Hmmm interesting. I think the dispatch error is because both tracker and observe are dispatching at the same time? (this is usually not allowed in flux to prev. cascading changes). I'm thinking if you comment out the tracker all together than it would eliminate the dispatch error? I'm not too sure about the order.
Yep this won't work for our flux use case. If you're making an update, it triggers but for example if you are watching for changes on the logged in user, you won't get an update when they login.
Closing.
I don't think it makes much of a difference but this might be easier to understand:
http://stackoverflow.com/questions/25999324/meteor-deps-autorun-vs-collection-observe