-
Notifications
You must be signed in to change notification settings - Fork 107
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
Best approach to keep pulling GET requests from backend server #127
Comments
Here is an idea, make a
|
I can lump my question in with this too since I think mine is similar. Lets say I have a page that needs to poll the server for updates. I was thinking on mount the component would dispatch an action saying "subcribe me to updates on the server". Then on unmount the component would dispatch the cancel action to stop it from happening. const pollingLogic = createLogic({
type: 'subscribe.me',
cancelType: 'unsubscribe.me',
process ({ http }, dispatch, _done) {
return intervalObservable(30000).pipe(
flatMap(() => http.get('/server'),
// how do I dispatch the action at this point to update component based on server data?
tap(data => dispatch({ type: 'udpatedpolling', payload: data }))
}
}) Mostly I am just confused if its weird my middleware would never call done. Or if I can even keep dispatching the events? |
Thanks for the question @hadim and @skbolton. @skbolton you are on the right track here. There are many ways to approach it, but you tackled it the way I would. If you just need to do the same dispatch on every response then you could do it like this If you need to do additional dispatching besides the results then see this example mergeMap is the new name for flatMap in rxjs@6 My first example just returns the observable and doesn't use dispatch and done. However if you need to do other dispatching besides just the results then you will want to include dispatch and done (even though you won't be calling done, just needed for now to set the arity right). Then you can dispatch the observable to kick things off. Eventually in a future version of redux-logic you'll be able to do a mix of returning an observable and dispatching, but currently it is one or the other. You could also have the observable return different types of actions but my second example is probably easier to follow for that scenario. |
Thanks for the response @jeffbski this library has been awesome so far. Just to complete my understanding and to get me the rest of the way there when I am testing this logic it would never actually call complete right? In other words return store.whenComplete(() => ...) wouldn't actually get fired right? This would be okay because I am using a library to fake time going by and I can still test it |
Thank you for this very detailed answer! That will be very useful. |
@skbolton yes, that is correct it would not complete unless you fire the cancelType, then it would actually complete. You are both welcome! |
@jeffbski need any help on this project for hacktoberfest? |
Thanks for offering @skbolton. I'll give it some thought. Probably the biggest need is for more docs, like specifically a nice guidebook, or recipebook for using redux-logic in a variety of common use cases. |
Not sure if this is an issue with my rxjs understanding or this library. I have code that was working well that looked like this. export const historySubscription = createLogic({
type: constants.SUBSCRIBE_TO_USER_HISTORY.ACTION,
cancelType: constants.SUBSCRIBE_TO_USER_HISTORY.CANCELLED,
warnTimeout: 0,
debounce: 500,
processOptions: {
successType: constants.FETCH_HISTORY.FULFILLED,
failType: constants.FETCH_HISTORY.REJECTED
},
process ({ http, action }) {
// create stream of events starting now and emitting every `x` milliseconds
return timer(0, action.payload.pollTime || 10000).pipe(
// concatMap waits for inner stream to complete and then concats the stream
// to the outer stream (timer in this case).
// since the inner stream is a http request that will emit complete when it is done
// this works perfectly
concatMap(() =>
http
.get(`/design-view/publish-histories/${action.payload.projectId}`)
.pipe(
map(http.getBody),
map(({ projectPublishHistory }) => ({
history: projectPublishHistory.history.reverse()
}))
)
)
)
}
}) I had to add the feature that a pending action would get dispatched (the export const historySubscription = createLogic({
type: constants.SUBSCRIBE_TO_USER_HISTORY.ACTION,
cancelType: constants.SUBSCRIBE_TO_USER_HISTORY.CANCELLED,
warnTimeout: 0,
debounce: 500,
processOptions: {
dispatchMultiple: true
},
process ({ http, action }, dispatch) {
// create stream of events starting now and emitting every `x` milliseconds
return timer(0, action.payload.pollTime || 10000).pipe(
// this is the pending on loading history action
tap(() => dispatch({ type: constants.FETCH_HISTORY.ACTION })),
// concatMap waits for inner stream to complete and then concats the stream
// to the outer stream (timer in this case).
// since the inner stream is a http request that will emit complete when it is done
// this works perfectly
concatMap(() =>
http
.get(`/design-view/publish-histories/${action.payload.projectId}`)
.pipe(
map(http.getBody),
map(({ projectPublishHistory }) => ({
history: projectPublishHistory.history.reverse()
}))
)
)
)
.subscribe({
next (payload) {
return dispatch({ type: constants.FETCH_HISTORY.FULFILLED, payload })
},
error (err) {
return dispatch({ type: constants.FETCH_HISTORY.REJECTED, payload: err, error: true })
}
})
}
}) This works except the cancellation stopped working. I was able to get it back by doing this. export const historySubscription = createLogic({
type: constants.SUBSCRIBE_TO_USER_HISTORY.ACTION,
cancelType: constants.SUBSCRIBE_TO_USER_HISTORY.CANCELLED,
warnTimeout: 0,
debounce: 500,
processOptions: {
dispatchMultiple: true
},
process ({ http, action, action$ }, dispatch) {
// create stream of events starting now and emitting every `x` milliseconds
return timer(0, action.payload.pollTime || 10000).pipe(
takeUntil(
action$.pipe(filter(act => act.type === constants.SUBSCRIBE_TO_USER_HISTORY.CANCELLED))
),
// this is the pending on loading history action
tap(() => dispatch({ type: constants.FETCH_HISTORY.ACTION })),
// concatMap waits for inner stream to complete and then concats the stream
// to the outer stream (timer in this case).
// since the inner stream is a http request that will emit complete when it is done
// this works perfectly
concatMap(() =>
http
.get(`/design-view/publish-histories/${action.payload.projectId}`)
.pipe(
map(http.getBody),
map(({ projectPublishHistory }) => ({
history: projectPublishHistory.history.reverse()
}))
)
)
)
.subscribe({
next (payload) {
return dispatch({ type: constants.FETCH_HISTORY.FULFILLED, payload })
},
error (err) {
return dispatch({ type: constants.FETCH_HISTORY.REJECTED, payload: err, error: true })
}
})
}
}) Is there something I am doing wrong or is this a bug? |
I think what you have is fine. By including the dispatch the automatic dispatchReturn was disabled and thus it wasn't automatically subscribing to your observable and that it wasn't getting cancelled. Cancellation should stop sending out the dispatch results, but the observable is probably still continuing. Compared with when you return the observable it subscribes for your and also cancels the observable automatically too. There's a couple ways of possibly simplifying this. One way would be to use the cancelled$ rather than creating your own. export const historySubscription = createLogic({
type: constants.SUBSCRIBE_TO_USER_HISTORY.ACTION,
cancelType: constants.SUBSCRIBE_TO_USER_HISTORY.CANCELLED,
warnTimeout: 0,
debounce: 500,
processOptions: {
dispatchMultiple: true
},
process ({ http, action, action$, cancelled$ }, dispatch) {
// create stream of events starting now and emitting every `x` milliseconds
return timer(0, action.payload.pollTime || 10000).pipe(
takeUntil(cancelled$),
// this is the pending on loading history action
tap(() => dispatch({ type: constants.FETCH_HISTORY.ACTION })),
// concatMap waits for inner stream to complete and then concats the stream
// to the outer stream (timer in this case).
// since the inner stream is a http request that will emit complete when it is done
// this works perfectly
concatMap(() =>
http
.get(`/design-view/publish-histories/${action.payload.projectId}`)
.pipe(
map(http.getBody),
map(({ projectPublishHistory }) => ({
history: projectPublishHistory.history.reverse()
}))
)
)
)
.subscribe({
next (payload) {
return dispatch({ type: constants.FETCH_HISTORY.FULFILLED, payload })
},
error (err) {
return dispatch({ type: constants.FETCH_HISTORY.REJECTED, payload: err, error: true })
}
})
}
}) Another idea that might work fine is to set dispatchReturn to true and then it should allow you to do both dispatching of the Fetch history action and handle what is emitted from the returned observable. Since it is subscribing automatically to the observable, it should cancel appropriately without additional help. export const historySubscription = createLogic({
type: constants.SUBSCRIBE_TO_USER_HISTORY.ACTION,
cancelType: constants.SUBSCRIBE_TO_USER_HISTORY.CANCELLED,
warnTimeout: 0,
debounce: 500,
processOptions: {
successType: constants.FETCH_HISTORY.FULFILLED,
failType: constants.FETCH_HISTORY.REJECTED,
dispatchMultiple: true,
dispatchReturn: true,
},
process ({ http, action }, dispatch) {
// create stream of events starting now and emitting every `x` milliseconds
return timer(0, action.payload.pollTime || 10000).pipe(
// this is the pending on loading history action
tap(() => dispatch({ type: constants.FETCH_HISTORY.ACTION })),
// concatMap waits for inner stream to complete and then concats the stream
// to the outer stream (timer in this case).
// since the inner stream is a http request that will emit complete when it is done
// this works perfectly
concatMap(() =>
http
.get(`/design-view/publish-histories/${action.payload.projectId}`)
.pipe(
map(http.getBody),
map(({ projectPublishHistory }) => ({
history: projectPublishHistory.history.reverse()
}))
)
)
)
}
}) |
Hi,
This lib looks super nice and I am tempting to integrate it into a project. I would like to know if you have an opinion on the best approach to keep pulling GET requests from backend server.
When the user login I need to start this infinite loop to keep getting data from the backend server at regular interval and cancel the loop when the user logout.
Then according to the type of message received by the backend, I would need to trigger some actions/logic.
The text was updated successfully, but these errors were encountered: