错误:[PrivateRoute] 不是 <Route> 组件。<Routes> 的所有子组件必须是 <Route> 或 <React.Fragment>

IT技术 javascript reactjs react-router-dom
2021-04-19 17:33:28

我正在使用 react-router v6 并为我的应用程序创建私有路由。

在 PrivateRoute.js 中,我有代码

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

在 route.js 中我写成

 ...
<PrivateRoute exact path="/" element={<Dashboard/>}/>
<Route exact path="/home" element={<Home/>}/>

我经历了同样的例子https://stackblitz.com/github/remix-run/react-router/tree/main/examples/auth?file=src/App.tsx

有什么我想念的吗?谢谢你。

6个回答

我今天遇到同样的问题,并根据此与下面的解决方案提出了非常有value的文章安德鲁·卢卡

在 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" />;
}

在 App.js 中(我已经在其他一些页面中作为示例):

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>
    
  );
}

在上面的路由中,这是私有路由:

<Route exact path='/' element={<PrivateRoute/>}>
      <Route exact path='/' element={<Home/>}/>
</Route>

如果授权成功,该元素将显示。否则,它将导航到登录页面。

如果使用最新版本,则exact不需要属性。
2021-06-09 17:33:28
@DallinRomney 在 React 中,不,当涉及到身份验证实现时,React 本身是相当不固执的,但是使用的任何库当然都可以提供自己的身份验证容器/包装器。这就是吸引人的部分。:) 它实际上与我在 v5 中使用的模式相同,我称之为“金门”路线,它是进入“围墙花园”路线的唯一身份验证点,现在每个人都不需要身份验证检查。
2021-06-10 17:33:28
@DrewReese 刚刚意识到您在谈论路线内的附加路线。如果主页是唯一需要授权的页面,那么您是对的,不需要子路由。如果多个路由需要相同的身份验证,那么将它们都放在同一个 PrivateRoute 中会很方便。
2021-06-17 17:33:28
啊,我读了那个博客,现在简单地呈现<Route element={<Home/>} />为私人出口的孩子更有意义这现在更吸引人了。我可以在某些用例中看到好处。
2021-06-20 17:33:28
@DrewReese 是否有某种内置的 Auth 组件?我不是 React 专家,所以我很想看到其他解决方案。在我的理解中,此示例中的 PrivateRoute 组件充当 Auth 组件
2021-06-20 17:33:28

只有Route组件可以是 的子代Routes如果您遵循 v6 文档,那么您将看到身份验证模式是使用包装器组件来处理身份验证检查和重定向。

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>
  }
/>

创建自定义Route组件的旧 v5 模式不再有效。使用您的代码/逻辑更新的 v6 模式可能如下所示:

const PrivateRoute = ({ children }) => {
  const authed = isauth() // isauth() returns true or false based on localStorage
  
  return authed ? children : <Navigate to="/Home" />;
}

并使用

<Route
  path="/dashboard"
  element={
    <PrivateRoute>
      <Dashboard />
    </PrivateRoute>
  }
/>
Dallin 的回答很好,但老实说,仅用 auth 组件包装目标组件并不能为您节省太多。如果有的话,它是一个更复杂的解决方案,因为它现在涉及渲染两个 Route组件并且Outlet只渲染单个路径。
2021-05-26 17:33:28
谢谢,这是我的解决方案,并且有效。
2021-06-13 17:33:28

只需将您的路由器组件设置为 element prop:

<Routes>
  <Route exact path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
  <Route path="/dashboard" element={<Dashboard />} />
</Routes>

您还可以检查从 v5 升级, https://reactrouter.com/docs/en/v6/upgrading/v5

我知道这并不完全是如何PirvateRoute工作的秘诀,但只是想提一下,新文档推荐了一种稍微不同的方法来使用 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;
};

ProtectedPage如果需要,您应该在内部添加更多路由

有关更多详细信息,请参阅文档示例另外,请查看Michael Jackson 的这篇笔记,其中介绍了一些实现细节。

react-router v6,一些语法糖:

{auth && (
  privateRoutes.map(route =>
    <Route
      path={route.path}
      key={route.path}
      element={auth.isAuthenticated ? <route.component /> : <Navigate to={ROUTE_WELCOME_PAGE} replace />}
    />
  )
)}