New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow using startWith/from/of inside epics. #254
Conversation
src/createEpicMiddleware.js
Outdated
@@ -45,6 +48,7 @@ export function createEpicMiddleware(epic, options = defaultOptions) { | |||
return output$; | |||
}) | |||
::switchMap(output$ => options.adapter.output(output$)) | |||
::mergeMap(action => of(action, asap)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm I'm pretty reluctant to schedule every action asap. Seems like it could create hard to understand behavior for people, as well as more complex stack traces--separately, I think ::observeOn(asap)
would be the more idiomatic way of achieving asap scheduling, though they both would have the same net result seemingly. Don't worry about changing it just yet, need to figure out out if this is the best solution in general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried using ::observeOn(asap)
first, but it broke the it('should throw if you provide a root epic that doesn\'t return anything)'
since exception was thrown from the asap
scheduler and not from createStore(..., applyMiddleware(...))
call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh right cause observeOn will schedule everything whereas mergeMap+of(a, asap) will just schedule next, not error/complete
Will need to think about this one some more, but my gut thinks the solution is to somehow wait until after the middleware is finished setting up before subscribing to the root epic. That's tricky because of the way the redux middleware API is designed as well as we want to be careful not to miss any actions dispatched synchronously outside of redux-observable (e.g. in server rendering cases this is common) I'm pretty reluctant to schedule all actions on asap scheduler cause that feels like it might cause other problems and make the normal flow harder to reason for people--it also wouldn't be as performant but I'm not as worried about that. btw this is definitely a bug. Your use case definitely should be supported, so thank you for bringing it up! I thought I had tested that, but seems I did not (didn't test the recursive nature) |
test/createEpicMiddleware-spec.js
Outdated
for (const _ of new Array(10)) { // eslint-disable-line no-unused-vars | ||
await (new Promise(setTimeout)); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use Observables to declaratively add these delays?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I will add change it.
Hmm, it turns out that there are 2 problems here:
Waiting until after middleware is initialized solves (1) but not (2). |
… now processed by epics. Closes redux-observable#253
eb74c42
to
92332c5
Compare
Hmm, too late. @jayphelps Fixed without changing schedulers now, please review. |
Any update on this? I think it may be the root cause of a tricky bug I'm struggling with in my app. |
@mpiroc Should be fairly easy to verify--check if you are emitting an action immediately on app start via startWith or concat, and another epic is listening for this action but not receiving it but your reducers are. This is a fairly odd pattern IMO, but I don't doubt there are some rare use cases for it. We're switching from a middleware to a store enhancer in #256. This is progressing, but admittedly slow because this is all volunteer work. |
Thanks @jayphelps, my bug turned out to be unrelated to this issue. |
@franekp I feel pretty bad that that is a pretty impressive PR, but has sat unmerged for so long. I'm sorry! It's still a use case I think we should support, I just don't have confidence yet this approach is the way to achieve it. I'm going to try to figure out #256 in the coming weeks, then we can circle back on this. |
No problem, I understand. I am glad you want to support this use case. |
…s now supported. fixes #253 closes #254, #259, #256 BREAKING CHANGE: To support synchronously emitting actions when an Epic starts up, along with other fairly complex recursive action use cases, your root Epic is now subscribed to using the Queue Scheduler, and then any actions you emit are also scheduled using the Queue Scheduler. It's possible that some of your Epics could be relying on the fact that an action was historically emitted without Queue scheduling, most likely unknowingly. If none of your Epics rely on the actions emitted by another Epic or itself, you should see no changes. As this is a complex topic to elaborate on, and the Queue Scheduler is not well known, you'll want to learn more here: https://redux-observable.js.org/MIGRATION.html
I believe this was fixed last year. Definitely lmk if not! 62a8c73 |
Closes #253