Error: [PrivateRoute] no es un componente <Route>. Todos los componentes secundarios de <Routes> deben ser <Route> o <React.Fragment>
Estoy usando React Router v6 y estoy creando rutas privadas para mi aplicación.
En el archivo PrivateRoute.js , tengo el código
import React from 'react';
import {Route,Navigate} from "react-router-dom";
import {isauth} from 'auth'
function PrivateRoute({ element, path }) {
const authed = isauth() // isauth() returns true or false based on localStorage
const ele = authed === true ? element : <Navigate to="/Home" />;
return <Route path={path} element={ele} />;
}
export default PrivateRoute
Y en el archivo route.js he escrito como:
...
<PrivateRoute exact path="/" element={<Dashboard/>}/>
<Route exact path="/home" element={<Home/>}/>
Revisé el mismo ejemplo: Ejemplo de autenticación de enrutador React: StackBlitz, archivo App.tsx
¿Se me escapa algo?
Me encontré con el mismo problema hoy y se me ocurrió la siguiente solución basada en este artículo muy útil de Andrew Luca.
En PrivateRoute.js:
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRoute = () => {
const auth = null; // determine if authorized, from context or however you're doing it
// If authorized, return an outlet that will render child elements
// If not, return element that will navigate to login page
return auth ? <Outlet /> : <Navigate to="/login" />;
}
En App.js (lo he dejado en algunas otras páginas como ejemplos):
import './App.css';
import React, {Fragment} from 'react';
import {BrowserRouter as Router, Route, Routes} from 'react-router-dom';
import Navbar from './components/layout/Navbar';
import Home from './components/pages/Home';
import Register from './components/auth/Register'
import Login from './components/auth/Login';
import PrivateRoute from './components/routing/PrivateRoute';
const App = () => {
return (
<Router>
<Fragment>
<Navbar/>
<Routes>
<Route exact path='/' element={<PrivateRoute/>}>
<Route exact path='/' element={<Home/>}/>
</Route>
<Route exact path='/register' element={<Register/>}/>
<Route exact path='/login' element={<Login/>}/>
</Routes>
</Fragment>
</Router>
);
}
En la ruta anterior, esta es la ruta privada:
<Route exact path='/' element={<PrivateRoute/>}>
<Route exact path='/' element={<Home/>}/>
</Route>
Si la autorización es exitosa, se mostrará el elemento. De lo contrario, navegará a la página de inicio de sesión.
Sólo Route
los componentes pueden ser hijos de Routes
. Si sigue los documentos de la versión 6, verá que el patrón de autenticación es utilizar un componente contenedor para manejar la verificación de autenticación y la redirección.
function RequireAuth({ children }: { children: JSX.Element }) {
let auth = useAuth();
let location = useLocation();
if (!auth.user) {
// Redirect them to the /login page, but save the current location they were
// trying to go to when they were redirected. This allows us to send them
// along to that page after they login, which is a nicer user experience
// than dropping them off on the home page.
return <Navigate to="/login" state={{ from: location }} />;
}
return children;
}
...
<Route
path="/protected"
element={
<RequireAuth>
<ProtectedPage />
</RequireAuth>
}
/>
El antiguo patrón v5 de crear Route
componentes personalizados ya no funciona. Un patrón v6 actualizado usando su código/lógica podría tener el siguiente aspecto:
const PrivateRoute = ({ children }) => {
const authed = isauth() // isauth() returns true or false based on localStorage
return authed ? children : <Navigate to="/Home" />;
}
y para usar
<Route
path="/dashboard"
element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
}
/>