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/>}/>
He pasado por el mismo ejemplo React-router Auth Example - StackBlitz, file 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.
Solo los componentes Route
pueden ser elementos secundarios de Routes
. Si sigue los documentos de v6, verá que el patrón de autenticación es usar 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 componentes de Route
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> } />
Sé que esta no es exactamente la receta para hacer que PirvateRoute
funcione, pero solo quería mencionar que los nuevos documentos recomiendan un enfoque ligeramente diferente para manejar este patrón con react-router v6:
<Route path="/protected" element={<RequireAuth><ProtectedPage /></RequireAuth>} />
import { Navigate, useLocation } from "react-router"; export const RequireAuth: React.FC<{ children: JSX.Element }> = ({ children }) => { let auth = useAuth(); let location = useLocation(); if (!auth.user) { return <Navigate to="/login" state={{ from: location }} />; } return children; };
y se supone que debe agregar más rutas dentro de ProtectedPage
si lo necesita.
Ver documentos y ejemplo para más detalles. Además, consulte esta nota de Michael Jackson que incluye algunos detalles de implementación.
React Router v6, algo de azúcar sintáctico:
{auth && ( privateRoutes.map(route => <Route path={route.path} key={route.path} element={auth.isAuthenticated ? <route.component /> : <Navigate to={ROUTE_WELCOME_PAGE} replace />} /> ) )}
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom"; function App() { return ( <Router> <Routes> <Route path="/" element={<h1>home page</h1>} /> <Route path="/seacrch" element={<h1>seacrch page</h1>} /> </Routes> </Router> ); } export default App;
El encabezado permanecerá en todas las páginas
import React from 'react'; import { BrowserRouter, Routes, Route } from "react-router-dom"; const Header = () => <h2>Header</h2> const Dashboard = () => <h2>Dashboard</h2> const SurveyNew = () => <h2>SurveyNew</h2> const Landing = () => <h2>Landing</h2> const App = () =>{ return ( <div> <BrowserRouter> <Header /> <Routes > <Route exact path="/" element={<Landing />} /> <Route path="/surveys" element={<Dashboard />} /> <Route path="/surveys/new" element={<SurveyNew/>} /> </Routes> </BrowserRouter> </div> ); }; export default App;
Simplemente configure el componente de su enrutador en elemento prop:
<Routes> <Route exact path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/dashboard" element={<Dashboard />} /> </Routes>
También puede verificar la actualización desde v5, https://reactrouter.com/docs/en/v6/upgrading/v5
puede usar la función para ruta privada
<Route exact path="/login" element={NotAuth(Login)} /> <Route exact path="/Register" element={NotAuth(Register)} /> function NotAuth(Component) { if (isAuth) return <Navigate to="/" />; return <Component />; }
para el error "[Navegar] no es un componente. Todos los componentes secundarios de deben ser un o <React.Fragment>"
use el siguiente método tal vez resuelto:
DefaultPage es cuando no hay un enrutador coincidente, salte a DefaultPage aquí, use <Route index element={} /> para reemplazar el
<Navegar a={ventana.ubicación.nombre de ruta + '/kanban'}/>
aquí está el enlace: https://reactrouter.com/docs/en/v6/getting-started/tutorial#index-routes
}/> }/> {/**/} } />Si está utilizando un segundo archivo para trabajar en su index.js. Aquí hay un fragmento de código más simple que puede ayudar a otros a entender mejor. Es bastante sencillo y no necesita "exacto" y "cambiar" para cambiar entre las rutas gracias a la nueva versión.
índice.js
import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; import "./index.css"; import App from "./App"; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById("root") );
Aplicación.js
Tenga en cuenta que debe importar { Rutas, Ruta } en lugar de { Ruta } (como estaba en versiones anteriores). Además, tenga en cuenta que en el archivo App.js, no es necesario volver a importar BrowserRouter.
import { Routes, Route } from "react-router-dom"; import AllPages from "./pages/AllPages"; import NewContactsPage from "./pages/ContactsPage"; import FavoritesPage from "./pages/Favorites"; function App() { return ( <div> <Routes> <Route path="/" element={<AllPages />} /> <Route path="/new-contacts" element={<NewContactsPage />} /> <Route path="/favorites" element={<FavoritesPage />} /> </Routes> </div> ); } export default App;
Complemento para reducir líneas de código, hacerlo más legible y bonito.
Esto podría ser solo un comentario, pero no tengo suficientes puntos, así que lo pondré como respuesta.
¡La respuesta de Dallin funciona, pero la respuesta de Drew es mejor! Y solo para completar la respuesta de Drew sobre estética, recomiendo crear un componente privado que tome componentes como accesorios en lugar de niños.
Ejemplo muy básico de archivo/componente de rutas privadas:
import { Navigate } from 'react-router-dom'; const Private = (Component) => { const auth = false; //your logic return auth ? <Component /> : <Navigate to="/login" /> }
Ejemplo de archivo de ruta:
<Routes> <Route path="/home" element={<Home />} /> <Route path="/user" element={<Private Component={User} />} /> </Routes>
Para elementos más largos
<Router> <div> <Navbar totalItems={cart.total_items}/> <Routes> <Route exact path='/'> <Route exact path='/' element={<Products products={products} onAddToCart={handleAddToCart}/>}/> </Route> <Route exact path='/cart'> <Route exact path='/cart' element={<Cart cart={cart}/>}/> </Route> </Routes> </div> </Router>