-
In my application, I have I was defining export const ASSERT_CURRENT_USER$ = CURRENT_USER$.pipe(
switchMap((user) =>
!user ? NEVER : of(user),
),
); The goal was to simplify queries that depend on the current user. By using the Thinking I was being clever, I decided to update the code to the following export const ASSERT_CURRENT_USER$ = CURRENT_USER$.pipe(
switchMap((user) =>
!user ? throwError(() => new NoCurrentUserError()) : of(user),
),
); I then added a export function catchNoCurrentUserError<I, T>(defaultValue: () => T) {
return pipe(
catchError<I, ObservableInput<T>>((err) => {
if (err instanceof NoCurrentUserError) {
return of(defaultValue());
}
throw err;
}),
);
} This greatly simplifies the code for some complex observables, since most of the code doesn't need to worry about handling a The problem is that after the error condition of the Is there any way to accomplish this goal? Separately, I'm guessing the current behavior in RXJS was intentional but it's not obvious to me why it's desirable? Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
how is In RxJS by default observables are lazy and unicast, meaning each subscriber will have their own side effect / state. When an observable throws an error, this error gets propagated all the way down to all subscribers, and all of those subscriptions are closed. As I understand, errors in RxJS were designed in a similar way of a regular If A posible "simple" solution is to make export function catchNoCurrentUserError<I, T>(defaultValue: () => T) {
return (source$: Observable<I>) => {
function handleError(err: any) {
if (err instanceof NoCurrentUserError) {
return source$.pipe(
startWith(defaultValue()),
catchError(handleError)
);
}
throw err;
}
return source$.pipe(
catchError(handleError)
);
};
} Essentially, when there's an error of type NoCurrentUserError this will act as a On React-RxJS we're currently working on a feature that will essentially solve this. It's still experimental and we're just trying it out, but essentially it will solve your problem by looking like this (again, experimental, API will change when we release... we have a few ideas that will help with versatility and type defs): // Assuming type of CURRENT_USER$ is `User | null`
export const ASSERT_CURRENT_USER$ = CURRENT_USER$.pipe(
sinkEffects(null) // This throws every null as an error, the result is Observable<User>
);
ASSERT_CURRENT_USER$.pipe(
... // Some stateful stuff,
liftEffects() // Will resurface the `null` as actual value
) the cool thing about this is that By now I would suggest to stick with the simple solution of |
Beta Was this translation helpful? Give feedback.
how is
CURRENT_USER$
defined?In RxJS by default observables are lazy and unicast, meaning each subscriber will have their own side effect / state. When an observable throws an error, this error gets propagated all the way down to all subscribers, and all of those subscriptions are closed. As I understand, errors in RxJS were designed in a similar way of a regular
throw new Error()
... that process is killed. You can catch the error and recover from it, but whatever happened there it's now dead.If
CURRENT_USER$
is not multicast, then even though it didn't throw an error, its only subscription did, which caused an unsubscription throughout the whole chain.A posible "simple" solution is to…