Error: [PrivateRoute] no es un componente <Route>. Todos los componentes secundarios de <Routes> deben ser <Route> o <React.Fragment>

Resuelto Rajanboy asked hace 2 años • 20 respuestas

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?

Rajanboy avatar Nov 06 '21 19:11 Rajanboy
Aceptado

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.

Dallin Romney avatar Nov 07 '2021 04:11 Dallin Romney

Sólo Routelos 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 Routecomponentes 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>
  }
/>
Drew Reese avatar Nov 07 '2021 06:11 Drew Reese