What is the best way to conditionally render routes in react-router based on user role. I have a case where not all roles have permission to view certain routes. And also I need to deal with subroutes. So if one of main routes is something like /posts I want only admin and student to access that route and its subroutes (posts/today for example). I am using react-router version 5.3.2.


Solution 1:

I has a similar issue with react-router-dom v6, but you can tweak it to your benefits

First create a source of truth wheither a user can or can't access some route, for roles based auth I'd think of a hook like

export function useUserRoles() {

    // some logic or api call to get the roles
    // for demonstration purposes it's just hard coded
    const userRoles: Array<typeof UserRoles[number]> = ['admin', 'root'];

    // return the current user roles
    return userRoles;
}

Then we make a component that can decide using that hook weither to render the route or redirect to login(or some page)

export function RolesAuthRoute({ children, roles }: { children: ReactNode, roles: Array<typeof UserRoles[number]> }) {

    const userRoles = useUserRoles();

    const canAccess = userRoles.some(userRole => roles.includes(userRole));


    if (canAccess)
        return (
            <Fragment>
                {children}
            </Fragment>
        );

    return (<Navigate to="/dashboard/login" />);
}

then the route defined wraps that component to act as a guard that decide if you can or can't access that route

            <Route
                path="users"
                element={
                    <Suspense fallback={<ProjectLayoutLoader />}>

                        <RolesAuthRoute roles={['admin']}>

                            <ProjectUsersPage />

                        </RolesAuthRoute>

                    </Suspense>
                } />