1

I have a fetch Epic that may return a 401 or 403 if the user doesn't have access to a server-side resource. I want to redirect during this Epic if this is the case.

Right now I'm doing this:

export const fetch$ = <T = any>(req: IRequest) =>
    from(performFetch<T>(req)).pipe(
        switchMap(res => of(res)),
        catchError(e => {
            if (e.status === 401 || e.status === 403) {
                window.location.replace(`/login?fwd=${encodeURIComponent(window.location.pathname)}`);
                return NEVER;
            }
            return of(e);
        })
    );

Where performFetch is just a simple function that does the fetch and returns a promise.

I'm using window.location.replace and so far it's working fine, but someone told me that it would mess up React.

I tried using connected-react-router and return a push action, but it wasn't doing the redirect.

Am I safe to continue doing it this way, or is there a better way?

wentjun
  • 40,384
  • 10
  • 95
  • 107
Zotoaster
  • 393
  • 2
  • 4
  • 15

1 Answers1

0

There shouldn't be a need to use window.location.replace so as you have installed react-router or connected-react-router, which handles component navigation within your application.

You can consider using either replace or push.

If you wish the return the action, you will have to wrap it using an of operator.

import { replace } from 'connected-react-router'.

export const fetch$ = <T = any>(req: IRequest) =>
  from(performFetch<T>(req)).pipe(
    switchMap(res => of(res)),
    catchError(e => {
      if (e.status === 401 || e.status === 403) {
        of(replace(`/login?fwd=${encodeURIComponent(window.location.pathname)}`));
      }
      return of(e);
    })
  );

Or, you can simply call replace/push as a side-effect, while returning something else.

export const fetch$ = <T = any>(req: IRequest) =>
  from(performFetch<T>(req)).pipe(
    switchMap(res => of(res)),
    catchError(e => {
      if (e.status === 401 || e.status === 403) {
        replace(`/login?fwd=${encodeURIComponent(window.location.pathname)}`);
        return NEVER;
      }
      return of(e);
    })
  );
wentjun
  • 40,384
  • 10
  • 95
  • 107
  • This is not working, and it might be because of my other code. I can see my state tree has the router in it, so that's there. The second example you gave seems to do nothing. The first one returns an action, but it's caught by my other epic which is calling fetch$, and it thinks that action is the fetch response. – Zotoaster Jan 26 '20 at 12:17
  • ahh I see.. In that case, the first example might lead you closer to something. What is happening in the other code you stated? – wentjun Jan 26 '20 at 12:56