0

I am building an app using Ionic React and Supabase. I have some conditional routes where the conditions are based on a context variable (auth.session). The variable however is null at the time of evaluation, and only gets set by the Supabase client in a useEffect in my authContextProvider after the redirect to the sign in page has already happened.

Currently

When there is a session and I navigate to /home, the router navigates to /sign-in.

Wanted outcome

When there is a session and I navigate to /home, the router navigates to /home.

src/index.tsx

...
root.render(
  <React.StrictMode>
    <AuthContextProvider>
      <App />
    </AuthContextProvider>
  </React.StrictMode>
);
...

src/App.tsx

...
const App: React.FC = () => {
  const { auth } = useContext(AuthContext);

  function handleRefresh(event: CustomEvent<RefresherEventDetail>) {
    window.location.reload();
  }

  return (
    <IonApp>
      <IonContent>
        <IonReactRouter>
          <IonRouterOutlet id="auth">
            <Switch>
              <Route exact path="/sign-in" component={SignIn} />
              <IonSplitPane contentId="main">
                <Menu />
                <IonRouterOutlet id="main">
                  <Route
                    exact
                    path="/home"
                    render={() => {
                      console.log(auth.session ? "Session" : "No session");
                      return auth.session ? (
                        <Home />
                      ) : (
                        <Redirect to="/sign-in" />
                      );
                    }}
                  />
                  <Redirect exact from="/" to="/home" />
                </IonRouterOutlet>
              </IonSplitPane>
            </Switch>
          </IonRouterOutlet>
        </IonReactRouter>
      </IonContent>
    </IonApp>
  );
};

console

No session

However in state:

enter image description here

src/components/AuthContextProvider.tsx

function AuthContextProvider({ children }: PropsWithChildren) {
  const [auth, dispatch] = useReducer(authReducer, {
    user: null,
    session: null,
  });

  useEffect(() => {
    supabase.auth.getSession().then(({ data }) => {
      dispatch({
        type: AuthReducerActions.set_auth,
        payload: data.session,
      });
    });

    const { data: authListener } = supabase.auth.onAuthStateChange(
      (event, session) => {
        dispatch({
          type: AuthReducerActions.set_auth,
          payload: session,
        });
      }
    );

    return () => {
      authListener.subscription.unsubscribe();
    };
  }, []);

  return (
    <AuthContext.Provider value={{ auth, dispatch }}>
      {children}
    </AuthContext.Provider>
  );
}

src/reducers/authReducer.ts

export default function authReducer(
  prevState: Auth,
  action: AuthReducerAction
): Auth {
  switch (action.type) {
    case AuthReducerActions.set_auth: {
      return {
        ...prevState,
        user: action.payload?.user ?? null,
        session: action.payload,
      };
    }
    case AuthReducerActions.sign_out: {
      return {
        ...prevState,
        user: null,
        session: null,
      };
    }
    default: {
      return prevState;
    }
  }
}

My thought was that when auth.session is set, that would trigger a rerender by the router. But apparently, it is only executed immediately and then forgets about the context. This solution using firebase, which is pretty similar to Supabase anyway uses an extra boolean in a hook. Based on that a loading spinner gets rendered or the actual app. If I do this I need to find a way of splitting the auth router and main router.

How would you approach this? Thanks in advance

HotFix
  • 157
  • 1
  • 11
  • *If I do this I need to find a way of splitting the auth router and main router.* Not clear what you mean, but probably not. No. If you need to wait for content to load before making a routing decision, you should probably just display a loading spinner. Technically you could redirect to the login page, then later if the session exists redirect back to the home page... but that just seem worse. – super Mar 20 '23 at 12:13

0 Answers0