getComments is async function. When it returns an error, I want to handle it through catchError. But I always execute map() and never execute catchError.
Why and How to fix this?
from(getComments(action.payload.url)).pipe(
map((comments: IComments[]) => commentsActions.fetch.done({ params: action.payload.url, result: { comments } })),
// TODO: 以下ではError handlingができない
catchError(error => of(commentsActions.fetch.failed({ params: action.payload.url, error: { hasError: true } }))),
),
and
export const getComments = async (url: string) => {
return await fetch(url)
.then(response => response.json())
.then(comments => comments)
.catch((e: string) => throwError(e));
}
Thanks in advance.
I handle error with ajax and it works.
https://github.com/redux-observable/redux-observable/blob/master/docs/recipes/ErrorHandling.md
Related
Demo: https://stackblitz.com/edit/rxjs-unsubscribe-issue?file=index.ts
Below code is not working
Error: Cannot read property 'unsubscribe' of undefined
const a = (): Observable<any> =>
new Observable(sub => {
sub.next(1);
return () => {
console.log('unsubscribe');
};
});
const observer = a().subscribe(
value => {
console.log('Subscription');
observer.unsubscribe();
},
e => console.log(e),
() => console.log('complete')
);
But the following code is working
const b = (): Observable<any> =>
new Observable(sub => {
setTimeout(()=>sub.next(1),0);
return () => {
console.log('unsubscribe');
};
});
const observer2 = b().subscribe(
value => {
console.log('Subscription b');
observer2.unsubscribe();
},
e => console.log(e),
() => console.log('complete')
);
Help me understand the reason behind it
as you mentioned in the title of your question, the first example is synchronous, so you get the first value while still inside of the .subscribe() method. Naturally, observer, which is supposed to have a Subscription object hasn't been initialized yet.
If you want to unsubscribe after receiving a single value I would suggest to use .take(1)
I am trying to combine fetch API and promises
When I do this, everything works
queryAPI(currency, cryptocurrency){
const url = fetch('https://api.coinmarketcap.com/v1/ticker/')
.then(response => response.json())
.then(data => console.log(data));
}
However, when I try to store it in a variable, the promise keeps pending
queryAPI(currency, cryptocurrency){
const url = fetch('https://api.coinmarketcap.com/v1/ticker/')
.then(response => {
const user = response.json()
console.log(user);
});
}
1) What am I doing wrong?
2) Is there any way I can get the value of the "user" outside of the function?
Thanks
The .json method also returns a promise. You have to call .then once again to get the final result:
queryAPI(currency, cryptocurrency){
const url = fetch('https://api.coinmarketcap.com/v1/ticker/')
.then(response => response.json())
.then(user => console.log(user))
}
so you could return the chained .thens from the queryAPI method and use it in the rest of your code:
const queryAPI = (currency, cryptocurrency) => {
return new Promise((resolve, rej) => {
return fetch('https://api.coinmarketcap.com/v1/ticker/')
.then(response => response.json())
.then(data => resolve({user: data, currency: 'EUR'}))
.catch(e => rej(e))
});
};
queryAPI('EU', 'bitcoin').then(data => {
console.log(data.user);
console.log(data.currency)
});
I've written the Effect below to make requests for each item in the array, and when one fails, the error isn't handled and the observable stream completes resulting actions not triggering effects any further.
Effect:
#Effect() myEffect$ = this.actions$.pipe(
ofType<myAction>(myActionTypes.myAction),
mergeMapTo(this.store.select(getAnArray)),
exhaustMap((request: any[]) => {
return zip(...request.map(item => {
return this.myService.myFunction(item).pipe(
map(response => {
return this.store.dispatch(new MyActionSuccess(response))
}),
catchError(error => {
return Observable.of(new MyActionFailure(error));
})
)
}))
})
How do I handle the error in this case?
I am trying to get my NgRX effect to return an action object. The action object indicates a "success", and needs to return all retrieved institutions as part of the payload. How do I do this? Please note that the block inside of the mergeMap does not work. I need to return all the retrieved institutions as part of a payload after retrieving them.
#Effect()
getInstitutions$ = this.actions$
.ofType(institutionActions.InstitutionActionTypes.GetInstitutions)
.pipe(
switchMap(() => {
const institutions = this.getInstitutions();
console.log(institutions);
return this.getInstitutions();
}),
mergeMap((institutions: Institution[]) => {
// return institutions;
return {
type: institutionActions.InstitutionActionTypes.GetInstitutionsSuccess,
payload: institutions
};
})
);
You have to operate on this.getInstitutions() as in:
#Effect()
getInstitutions$ = this.actions$
.ofType(institutionActions.InstitutionActionTypes.GetInstitutions)
.pipe(
switchMap(() => {
return this.getInstitutions().pipe(
map(institutions => ({
type: institutionActions.InstitutionActionTypes.GetInstitutionsSuccess,
payload: institutions
})),
catchError(_ => ...) //don't forget to handle errors
)
})
);
As a side note, I would encourage you to use action creators, instead of creating action objects "all over the place" - Let’s have a chat about Actions and Action Creators within NgRx
How about using "map" instaed mergeMap. Can you try following?
#Effect()
getInstitutions$ = this.actions$
.ofType(institutionActions.InstitutionActionTypes.GetInstitutions)
.pipe(
switchMap(() => {
const institutions = this.getInstitutions();
console.log(institutions);
return this.getInstitutions();
}),
map((institutions: Institution[]) => {
// return institutions;
return {
type: institutionActions.InstitutionActionTypes.GetInstitutionsSuccess,
payload: institutions
};
})
);
Hope that helps!
I wrote a generic request method that is supposed to show a loading indicator while the request is running. If an error occurs (like 404), I display the message in .catch and then return Observable.empty(), so that the following code doesn't crash (since no data is returned).
The big problem is that then .finally won't be called either. Is that a bug? Is there a workaround? Here's my code:
res = Observable
.of(true)
.do(() => this.store.dispatch(new ShowLoadingIndicatorAction()))
.switchMap(() => this.http.get(url, { headers: this.headers }))
.publishReplay(1)
.refCount()
.catch(error => {
this.messages.handleRequestError(error);
return Observable.empty();
})
.finally(() => this.store.dispatch(new HideLoadingIndicatorAction()));
// then later:
res.subscribe(doStuffWithData);
What RxJS-version are you using? It does works fine in this example:
const res$ = Rx.Observable
.of(true)
.switchMap(() => Rx.Observable.throw("Rest Error"))
.publishReplay(1)
.refCount()
.catch(error => Rx.Observable.empty())
.finally(() => console.log("Calling Finally!"));
res$.subscribe(console.info);
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>