带有react-router v6 的受保护路由

IT技术 reactjs react-router react-router-dom
2021-04-14 17:47:58

使用 react-router 的新版本 6 编写 ProtectedRoute 的正确方法是什么?我写了这个,但它不是一条路线

const PrivateRoute = ({ component: Component, ...props }) => {   
  if (!Component) return null;

  return props.isAuthenticated
    ? <Component />
    : <Navigate to={props.redirectLink} /> }

export default PrivateRoute;
6个回答

这是我使用useRoutes实现私有路由的工作示例

应用程序.js

import routes from './routes';
import { useRoutes } from 'react-router-dom';

function App() {
  const { isLoggedIn } = useSelector((state) => state.auth);

  const routing = useRoutes(routes(isLoggedIn));

  return (
    <>
      {routing}
    </>
  );
}

路由.js

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

const routes = (isLoggedIn) => [
  {
    path: '/app',
    element: isLoggedIn ? <DashboardLayout /> : <Navigate to="/login" />,
    children: [
      { path: '/dashboard', element: <Dashboard /> },
      { path: '/account', element: <Account /> },
      { path: '/', element: <Navigate to="/app/dashboard" /> },
      {
        path: 'member',
        element: <Outlet />,
        children: [
          { path: '/', element: <MemberGrid /> },
          { path: '/add', element: <AddMember /> },
        ],
      },
    ],
  },
  {
    path: '/',
    element: !isLoggedIn ? <MainLayout /> : <Navigate to="/app/dashboard" />,
    children: [
      { path: 'login', element: <Login /> },
      { path: '/', element: <Navigate to="/login" /> },
    ],
  },
];

export default routes;
@fmsthird ...确定您是否已经使用过 redux。
2021-05-23 17:47:58
这个成功了。我正在寻找useRoutes()实现。谢谢!
2021-05-28 17:47:58
这是唯一一个我认为在这里有意义的...
2021-06-10 17:47:58
我收到这个错误!错误:useRoutes() 只能在 <Router> 组件的上下文中使用。我已经用路由器包装了
2021-06-19 17:47:58

我从以下示例中获取react-router-domhttps : //github.com/remix-run/react-router/blob/main/examples/auth/README.md

然后修改成这个https://stackblitz.com/edit/github-5kknft?file=src%2FApp.tsx

export default function App() {
  return (
    <AuthProvider>
      <Routes>
        <Route element={<Layout />}>
          <Route path="/" element={<PublicPage />} />
          <Route path="/public" element={<PublicPage />} />
          <Route path="/login" element={<LoginPage />} />
          <Route element={<RequireAuth />}>
            <Route path="/protected" element={<ProtectedPage />} />
            <Route path="/dashboard" element={<Dashboard />} />
          </Route>
        </Route>
        <Route path="*" element={<NotFound />} />
      </Routes>
    </AuthProvider>
  );
}
function RequireAuth() {
  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 <Outlet />;
}

您需要编写一个小包装器并使用Navigate组件进行重定向。您还需要渲染路线

const Container = ({Component, redirectLink, isAuthenticated, ...props}) => {
  if(!isAuthenticated) {
       return <Navigate to={redirectLink} />;
   }
   
   return <Component {...props} />
}
const PrivateRoute = ({ component: Component, redirectLink, isAuthenticated, path, ...props }) => {   

  return (
    <Route
        path={path}
        element={<Container redirectLink={redirectLink} isAuthenticate={isAuthenticated} Component={Component} />}
    />
)

export default PrivateRoute;

您可以在此处找到迁移指南 the github docs

更新了解决方案
2021-06-03 17:47:58
warning.js:24 您应该在 useEffect 中调用 navigate(),而不是在您的组件首次呈现时调用。
2021-06-10 17:47:58

这是一个工作示例。

import React from 'react';
import { Route, Navigate } from 'react-router-dom';

const PrivateRoute = ({ component: Component, redirectTo, isAuth, path, ...props }) => {
    if(!isAuth) {
        return <Navigate to={redirectTo} />;
    }
    return <Route path={path} element={<Component />} />
};

export default PrivateRoute;

用法:

<Routes>
     <Route path="app" element={<DashboardLayout />}>
         <PrivateRoute isAuth={true} path="account" component={AccountView}  redirectTo='/login'/>
     </Route>
 </Routes>
这不再适用于 react router v6.0.2
2021-06-04 17:47:58

都是不错的选择。您还可以根据身份验证状态(或任何其他状态)简单地呈现不同的路由处理。您不必使用原始 Javascript 对象方法。

不要忘记您可以使用立即调用的匿名内部函数(() => COMPONENT)()来动态决定哪个组件处理特定的<Route/>.

这些示例可能还没有出现在初步文档中,v6因为处理 private <Route/>s 实际上非常简单。

例如

<Routes>
      {state.authed ?
        // Wait until we have the current user...
        currentUser ?
          <Route
            path='/'
            element={(() => {
              // Show a "no access" message if the user is NOT an App Admin doesn't have access to any schools at all (which includes not having access to anything INSIDE any school either)
              if (!currentUser.appAdministrator && currentUser.schoolIds?.length === 0) return <AdminNoAccess />
              return <Outlet />
            })()}
          >
            <Route
              path='/'
              element={(() => {
                // If the user is a super user, we return the <SuperAdmin /> component, which renders some of its own routes/nav.
                if (currentUser.appAdministrator) return <SuperAdmin />
                return <Outlet />
              })()}
            >
              <Route
                path='schools'
                element={(() => {
                  if (currentUser.schoolIds?.length === 1) {
                    return <Navigate to={`schools/schoolId`} />
                  } else {
                    return <AdminSchools />
                  }
                })()}
              />

              <Route path='users' children={<Users />} />
            </Route>

            <Route path={`schools/:schoolId`} element={<AdminSchool />} />

            <Route path='*' element={<Navigate to='schools' />} />
          </Route>
          :
          null
        :
        <>
          <Route path='login' element={<Login />} />
          <Route path='signup' element={<Signup />} />
          <Route path='forgot-password' element={<ForgotPassword />} />
          <Route path='reset-password' element={<ResetPassword />} />

          <Route path='*' element={<Navigate to='login' />} />
        </>
      }
    </Routes>