I have this simple PrivateRoute setup that I'm looking to extend, using react-router-dom 6.3
import { Navigate } from 'react-router-dom';
import { useAppSelector } from '../../../hooks/redux/hooks';
const PrivateRoute = ({ page }: { page: JSX.Element}) => {
const { isAuthenticated } = useAppSelector((state) => state.auth);
return isAuthenticated ? page : <Navigate replace to='/login' />
}
export default PrivateRoute
Which gets used as follows:
<Route path='/' element={<PrivateRoute page={<Dashboard/>} />} />
What I would like is to add two new parameters: a 'permissions' parameter as a string array and specify a 'redirect' parameter as a nullable string.
<Route path='/' element={<PrivateRoute page={<Dashboard/>} permissions={['admin']} redirect='' />} />
I tried the following:
const PrivateRoute = ({ page }: { page: JSX.Element}, permissions: string[], redirect?: string) => {
}
It didn't error, but I also couldn't add the two new parameters in as I thought I could as in the 2nd to last example.
How can I achieve this?
CodePudding user response:
React components take up to a single props object as an argument. You need to add the additional props and types to this argument.
interface PrivateRouteProps {
page: JSX.Element;
permissions: string[];
redirect?: string;
}
const PrivateRoute = ({ page, permissions = [], redirect }: PrivateRouteProps) => {
...
}
I think you're going about route protection a bit incorrectly though. The more established pattern is to create a layout route that handles checking the authentication status and renders an Outlet
component for nested routes or the Navigate
component to redirect.
Example:
import { Navigate, Outlet } from 'react-router-dom';
interface PrivateRouteProps {
permissions: string[];
redirect?: string;
}
const PrivateRoutes = ({ permissions = [], redirect = "/" }: PrivateRouteProps) => {
const location = useLocation();
...
if (checkingPermission) {
return null; // or loading indicator/spinner/etc
}
return hasPermission
? <Outlet />
: <Navigate to={redirect} replace state={{ from: location }} />;
}
...
<Routes>
<Route element={<PrivateRoute permissions={['admin']} redirect='/login' />}>
<Route path='/' element={<Dashboard />} />
... other protected routes by role
</Route>
... other unprotected routes
</Routes>