I have seen many questions about this but none seem to work for me because they are old. The packages have been updated and the solutions for this have been stripped out. I do not want to use functional components to solve this.
I'm trying to create a private route with ReactJS and Typescript:
"react": "^17.0.2",
"react-router-dom": "^6.2.1",
"typescript": "^4.5.5",
But when I try to extend a Route:
export class PrivateRoute extends Route<PrivateRouteProps> {
public render(): JSX.Element {
return (
// ...
);
}
}
I get an error saying that I can't extend Route
:
Type '(_props: PathRouteProps | LayoutRouteProps | IndexRouteProps) => ReactElement<any, string | JSXElementConstructor> | null' is not a constructor function type.ts(2507)
And when I try to wrap a component around Route
:
export class PrivateRoute extends Component<PrivateRouteProps> {
public render(): JSX.Element {
return (
// ...
<Route />
// ...
);
}
}
It let's me build and even run but I get a runtime error:
Uncaught Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
Is there a correct way to do this? If not, is there a workaround for this without using functional components?
EDIT #1:
<Provider store={authStore}>
<BrowserRouter>
<Routes>
<Route path='/' element={<MainPage />} />
<Route path='/login' element={<LoginPage />} />
<PrivateRoute path='/dashboard' element={<DashboardPage />} />
<Route path='*' element={<NotFoundPage />} />
</Routes>
</BrowserRouter>
</Provider>
EDIT #2:
For future reference: I have solved this using @SlothOverlord's answer but translated from functional component. Also, I'm using redux to fill the props.
private.outlet.tsx:
export class PrivateOutlet extends Component<AuthenticationProps> {
public render(): JSX.Element {
const user = this.props.user;
if (user) { // Check if logged in
return (
<>
{this.props.children}
<Outlet />
</>
);
}
return <Navigate to="/login" replace />; // Go back to login if not logged in
}
}
public.outlet.tsx:
export class PublicOutlet extends Component<AuthenticationProps> {
public render(): JSX.Element {
const user = this.props.user;
if (!user) { // Check if logged in
return (
<>
{this.props.children}
<Outlet />
</>
);
}
return <Navigate to="/" replace />; // Go to protected route if logged in
}
}
The routes I kept the same as in the answer.
EDIT #3:
Regarding the [duplicate] status: The question linked does not solve the problem for the versions stated at the beginning of the post. As @SlothOverlord stated at the beginning of his answer:
Routes work different in v6.
Not only that but Redirect
does not exist in version 6. Many things are different. The decision to mark it duplicate was based on nothing except keyword matching of a flagging trigger happy mod.
This site is becoming a haven for self-important, misanthropic bullies that find in moderation a way to punish people for their own frustrations.