繁体   English   中英

错误:[PrivateRoute] 不是<route>成分。 的所有子组件<routes>必须是一个<route>或者<react.fragment></react.fragment></route></routes></route>

[英]Error: [PrivateRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

我正在使用 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/>}/>

我已经完成了相同的示例React-router Auth Example - StackBlitz,文件 App.tsx

有什么我想念的吗?

我今天遇到了同样的问题,并根据Andrew Luca的这篇非常有用的文章提出了以下解决方案

在 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>

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

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

补充减少代码行数,使其更具可读性和美观性。

这可能只是一个评论,但我没有足够的分数,所以我会把它作为答案。

达林的回答有效,但德鲁的回答更好! 为了完成 Drew 关于美学的回答,我建议创建一个私有组件,将组件作为道具而不是子组件。

私有路由文件/组件的非常基本的示例:

import { Navigate } from 'react-router-dom';

const Private = (Component) => {
    const auth = false; //your logic

    return auth ? <Component /> : <Navigate to="/login" />
}

路由文件示例:

<Routes>
    <Route path="/home" element={<Home />} />
    <Route path="/user" element={<Private Component={User} />} />
</Routes>

我知道这并不完全是让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 的这篇笔记,其中介绍了一些实现细节。

只需将您的路由器组件设置为 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

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

现在是 2022 年,我做了类似下面的事情:

// routes.tsx

import { lazy } from "react";
import { Routes, Route } from "react-router-dom";
import Private from "./Private";
import Public from "./Public";

const Home = lazy(() => import("../pages/Home/Home"));
const Signin = lazy(() => import("../pages/Signin/Signin"));

export const Router = () => {
  return (
    <Routes>
      <Route path="/" element={Private(<Home />)} />
      <Route path="/signin" element={Public(<Signin />)} />
    </Routes>
  );
};
// Private.tsx

import { Navigate } from "react-router-dom";
import { useEffect, useState } from "react";

function render(c: JSX.Element) {
  return c;
}

const Private = (Component: JSX.Element) => {
  const [hasSession, setHasSession] = useState<boolean>(false);

  useEffect(() => {
    (async function () {
      const sessionStatus = await checkLoginSession();

      setHasSession(Boolean(sessionStatus));
    })();
  }, [hasSession, Component]);


  return hasSession ? render(Component) : <Navigate to="signin" />;
};

export default Private;

希望这可以帮助!

我尝试了所有答案,但它总是显示错误:

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

但我找到了解决方案)))

在 PrivateRoute.js 文件中:

import React from "react"; import { Navigate } from "react-router-dom"; 
import {isauth}  from 'auth' 

const PrivateRoute= ({ children }) => {
 const authed = isauth()

  return authed  ? children : <Navigate to={"/Home" /> };

export default ProtectedRoute;

在 route.js 文件中:

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

Routes的子项需要是Route元素,因此我们可以更改ProtectedRoute

export type ProtectedRouteProps = {
    isAuth: boolean;
    authPath: string;
    outlet: JSX.Element;
};

export default function ProtectedRoute({
    isAuth,
    authPath,
    outlet,
}: ProtectedRouteProps) {
    if (isAuth) {
        return outlet;
    } else {
        return <Navigate to={{pathname: authPath}} />;
    }
}

然后像这样使用它:

const defaultProps: Omit<ProtectedRouteProps, 'outlet'> = {
  isAuth: //check if user is authenticated,
  authPath: '/login',
};

return (
  <div>
    <Routes>
        <Route path="/" element={<ProtectedRoute {...defaultProps} outlet={<HomePage />} />} />
    </Routes>
  </div>
);

如果您使用第二个文件来处理您的 index.js 。 这是一个更简单的代码片段,可以帮助其他人更好地理解。 这非常简单,并且由于新版本,您不需要“精确”和“切换”在路径之间进行更改。

index.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")
);

应用程序.js

请注意,您需要导入 { Routes, Route } 而不是 { Route } (就像在以前的版本中一样)。 另外请注意,在 App.js 文件中,无需再次导入 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;

这是创建私有路由的简单方法

import React from 'react'
import { Navigate } from 'react-router-dom'
import { useAuth } from '../../context/AuthContext'

export default function PrivateRoute({ children }) {
  const { currentUser } = useAuth()

  if (!currentUser) {
    return <Navigate to='/login' />
  }

  return children;
}

现在,如果我们想将私有路由添加到仪表板组件,我们可以应用此私有路由,如下所示

<Routes>
  <Route exact path="/" element={<PrivateRoute><Dashboard /></PrivateRoute>} />
</Routes>

您已经传递了element={<Dashboard/>}并且这样做实际上是调用了构造函数并创建了该组件,这是您的第一个错误。 你想做element={Dashboard}

第二件事是,当您创建私有路由时,您将不再使用Route ,而是直接渲染您传递给它的组件, PrivateRoute已经是一个路由。 你想要这样的模式:

const AuthRoute = ({Component, ...otherProps) => {
  const auth = // check auth

  return auth ? <Component/> : <Redirect to='/login'/>
}

这并不完全正确,但它是为了向您展示如何传递主要组件。 如果您使用打字稿,您还可以在 auth 路由上使用RouteComponentProps来强调它本身就是一个路由。

在你的情况下,你得到的错误是因为element={ele}和你已经通过element={<Dashboard/>}传递的已经构造的组件。

对于较长的元素

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

标题将保留在所有页面上

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;

您可以将功能用于私人路线

<Route exact path="/login" element={NotAuth(Login)} />
<Route exact path="/Register" element={NotAuth(Register)} />

function NotAuth(Component) {
  if (isAuth) return <Navigate to="/" />;
  return <Component />; 
}

从您的项目中移除 PrivateRoute 组件并在您的 App.js 文件中使用以下代码:

import {Navigate} from "react-router-dom";
import {isauth}  from 'auth'

...

<Route exact path="/home" element={<Home/>}/>
<Route exact path="/" element={isauth ? <Dashboard/> : <Navigate to="/Home"  />}/>
<Route path='/' element={<Navigate to="/search" />} />

本文中的解决方案 1 和 2 都对我有用

我正在使用“react-router-dom”:“^6.3.0”,这就是我的做法

PrivateRoute 组件和路由

   import {Route} from "react-router-dom";

    const PrivateRoute = ({ component: Compontent, authenticated }) => {
      return authenticated ? <Compontent /> : <Navigate to="/" />;
    }
    
    <Route 
          path="/user/profile" 
          element={<PrivateRoute authenticated={true} component={Profile} />} />

对于错误“[Navigate] 不是组件。所有组件子级必须是 a 或 <React.Fragment>”

使用以下方法也许可以解决:

DefaultPage是当没有匹配到router时,跳转到DefaultPage这里用<Route index element={} />代替

<导航到={window.location.pathname + '/看板'}/>

这是链接: https ://reactrouter.com/docs/en/v6/getting-started/tutorial#index-routes

}/> }/> {/**/} } />
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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM