Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Ionic (v5): IonReactRouter & IonRouterOutlet Not Working as Expected

I'm fairly new to React and Ionic. What I'm attempting to accomplished is to create a "protected route". I create a simple context called AuthContext:

import { createContext, Dispatch } from 'react';

/**
 * Context interface for AuthAuthentication/Authorization
 *
 * @property isAuthenticated
 * @property dispatch
 *
 * @interface
 */
interface AuthDefaultContext {
    isAuthenticated: boolean;
    dispatch: Dispatch<any>
}

/**
 * Authentication/Authorization context for managing
 * authenticating/ed and authorizing/ed users
 */
export const AuthContext = createContext<AuthDefaultContext>({
    isAuthenticated: false,
    dispatch: () => {}
});

and FunctionalComponent called ProtectedRoute:

interface ProtectedRouteProps {
    ProtectedComponent: FunctionComponent,
    routePath: string
}

export const ProtectedRoute: FunctionComponent<ProtectedRouteProps> = ({ ProtectedComponent, routePath }) => {

    useEffect(() => {
        console.log(`loading protected route '${routePath}' with component ${ProtectedComponent.name}`)
    }, [ProtectedComponent, routePath] );

    return (
        <AuthContext.Consumer>
            {
                ({ isAuthenticated }) => (
                    <Route path={ routePath } render={ () => isAuthenticated ? <ProtectedComponent/> : <Redirect to="/login" /> }/>
                )
            }
        </AuthContext.Consumer>
    );
}

In my main app component I wrap the IonReactRouter inside the AuthContext.Provider like so:

        <IonApp>
            <AuthContext.Provider value={{ isAuthenticated: authenticated, dispatch: dispatch }}>
                <IonReactRouter>
                    <IonRouterOutlet>
                        <Route path="/login" component={ Login } exact={ true } />
                        <ProtectedRoute routePath="/welcome" ProtectedComponent={ Welcome }/>
                        <ProtectedRoute routePath="/search" ProtectedComponent={ Dummy }/>
                    </IonRouterOutlet>
                </IonReactRouter>
            </AuthContext.Provider>
        </IonApp>

The issue that I am having is that above works fine for the regular Route and first ProtectedRoute, but the /search/ does not work. The uri path changes in the browser url to /search but the dummy component doesn't render.

I noticed that if you swap <IonReactRouter> & <IonRouterOutlet> like so:

            <IonRouterOutlet>
                <IonReactRouter>
                    .....
                </IonReactRouter>
            </IonRouterOutlet>

all of the routes works but you lose the animation effect provided by the IonRouterOutlet. The navigation docs on Ionics website has the IonReactRouter wrapping IonRouterOutlet so I am assuming that's the correct implementation.

If I change the ProtectedRoute's to just the standard react Route all routes work fine with the animations. So the issue has to be with my Implementation of the ProtectedRoute component, I just can't figure it out. Any help would be most appreciated. Thank you!

UPDATE:

I still haven't found a solution for this issue, so I removed the IonRouterOutlet which seems to be the root cause. When doing so, everything works as expected. I posted this issue on the Ionic forum so when/if I get an answer, I'll post it here.

Thanks,

like image 669
Joseph Freeman Avatar asked Jan 26 '23 06:01

Joseph Freeman


2 Answers

IonRouterOutlet expects its children to be either Routes or "Route like", which means the children need to have the same basic props that a Route does.

So, for your ProtectedRoute, it should work if you rename your incoming props routePath to path and ProtectedComponent to component.

I put together a working sample repo starting with your code here: https://github.com/elylucas/ionic-react-protected-route

Let me know if that helps.

Thanks

like image 135
Ely Avatar answered Feb 03 '23 08:02

Ely


I've found that using the render prop on a Route in an IonRouterOutlet breaks it.

In your case you would have to replace the following:

<Route
  path={routePath}
  render={() => isAuthenticated ? <ProtectedComponent/> : <Redirect to="/login" />}
/>

With something like this:

{
  isAuthenticated ?
    <Route path={routePath} component={ProtectedComponent} /> :
    <Redirect to="/login" />
}
like image 31
Barry Michael Doyle Avatar answered Feb 03 '23 06:02

Barry Michael Doyle