'Role based react-router

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:[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>
                } />

Solution 2:[2]

i have two role "parent" and "manager" and i write this code and work it for me:

function App(props) {

  return (

          <div className="App ">
            <Routes>
                    <Route exact path="/" element={<Home />} />
             
           <Route exact path="/" element={<ProtectedRoute />}>
              <Route exact path="/admin" element={<StudentLists />} />
              <Route exact path="/student_pk_api/:id" element={<IdFilter />} />
              <Route exact path="/absentes" element={<AbsentStu />} />
              <Route exact path="/students_by_field_and_level_:grade_api/:studyfield_code" element={<FieldGradeFilter />} />
              <Route exact path="/absent_yesterday_api" element={<YesterdayAbs />} />
              <Route exact path="/absent_today_api" element={<TodayAbs />} /> 
           </Route>
           <Route exact path="/" element={<ProtectedUserRoute />}>
           <Route exact path="/users" element={<SchoolDit />} />
           </Route>
             </Routes>
          </div>
    

  );
}

for cheking roles i write two function:

for manager role:

const  ProtectedRoute = () => {
    const [manager, setmaneger] = useState(localStorage.getItem("role")==="manager"?true:null);

    return manager ? <Outlet /> : <Navigate to="/" />;
}

  export default ProtectedRoute

for parent role:

const  ProtectedUserRoute = () => {
   
    const [parent, setParent] = useState(localStorage.getItem("role")==="parent"?true:null);

    return parent ? <Outlet /> : <Navigate to="/" />;
}
export default ProtectedUserRoute

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mhd Louay Al-osh
Solution 2 maede