用新版本的react-router 6编写ProtectedRoute的正确方法是什么? 我写了这个,但这不是一条路线
const PrivateRoute = ({ component: Component, ...props }) => {
if (!Component) return null;
return props.isAuthenticated
? <Component />
: <Navigate to={props.redirectLink} /> }
export default PrivateRoute;
答案 0 :(得分:4)
这是我使用 useRoutes 实现私有路由的工作示例。
App.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}
</>
);
}
routes.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;
答案 1 :(得分:3)
您需要编写一个小的包装,并使用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
答案 2 :(得分:2)
所有不错的选择。您还可以根据身份验证状态(或任何其他状态)简单地呈现不同的路由处理。您不必使用原始 Javascript 对象方法。
不要忘记您可以使用立即调用的匿名内部函数 (() => COMPONENT)()
来动态决定哪个组件处理特定的 <Route/>
。
这些示例可能尚未包含在 v6
的初步文档中,因为处理私有 <Route/>
实际上非常简单。
例如
<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>
答案 3 :(得分:1)
这是一个可行的示例。
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>
答案 4 :(得分:1)
这是我最新的使用react-router v6 beta的实现。我不知道如何使用useRoutes实现受保护的路由。他们的文档应该添加一个示例,说明如何以两种方式实现受保护/专用路由。
ProtectedRoute组件
import React from 'react';
import PropTypes from 'prop-types';
import { Route } from 'react-router-dom';
import Forbidden from '../../views/errors/Forbidden';
import { useAuth } from '../../contexts/AuthContext';
const ProtectedRoute = ({ roles, element, children, ...rest }) => {
const { user, login } = useAuth();
if (!user) {
login();
return <></>;
}
if (roles.length > 0) {
const routeRoles = roles.map((role) => role.toLowerCase());
const userRoles = (user && user.roles ? user.roles : []).map((role) => role.toLowerCase());
if (miscUtils.intersection(routeRoles, userRoles).length === 0) {
return <Forbidden />;
}
}
return (
<Route element={element} {...rest}>
{children}
</Route>
);
};
ProtectedRoute.propTypes = {
roles: PropTypes.arrayOf(PropTypes.string),
element: PropTypes.element,
children: PropTypes.node,
};
ProtectedRoute.defaultProps = {
roles: [],
element: null,
children: null,
};
export default ProtectedRoute;
AppRoutes组件
import React from 'react';
import { Routes, Route, Navigate, Outlet } from 'react-router-dom';
import Login from './components/oauth/Login';
import Logout from './components/oauth/Logout';
import RenewToken from './components/oauth/RenewToken';
import ProtectedRoute from './components/ProtectedRoute';
import NotFound from './views/errors/NotFound';
import Index from './views/Index';
import MainContainer from './views/MainContainer';
import ViewUserProfile from './views/user/profile/ViewUserProfile';
import CreateUserProfile from './views/user/profile/CreateUserProfile';
import UpdateUserProfile from './views/user/profile/UpdateUserProfile';
import PartnerProfile from './views/partner/profile/PartnerProfile';
const AppRoutes = () => {
return (
<Routes>
{/* auth pages (important: do not place under /auth path) */}
<Route path="oauth/login" element={<Login />} />
<Route path="oauth/logout" element={<Logout />} />
<Route path="oauth/renew" element={<RenewToken />} />
<Route element={<MainContainer />}>
<Route path="/" element={<Index />} />
{/* protected routes */}
<ProtectedRoute path="user" element={<Outlet />}>
<Route path="/" element={<Navigate to="profile" replace />} />
<Route path="profile" element={<Outlet />}>
<Route path="/" element={<ViewUserProfile />} />
<Route path="create" element={<CreateUserProfile />} />
<Route path="update" element={<UpdateUserProfile />} />
</Route>
</ProtectedRoute>
<ProtectedRoute path="partner" roles={['partner']} element={<Outlet />}>
<Route path="/" element={<Navigate to="profile" replace />} />
<Route path="profile" element={<PartnerProfile />} />
</ProtectedRoute>
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
);
};
export default AppRoutes;
答案 5 :(得分:0)
这是一个稍微更友好的 TypeScript 实现,它重用了 react-router v6 中的 RouteProps
:
import React from 'react';
import { RouteProps } from 'react-router';
import { Route, Navigate } from 'react-router-dom';
import { useAuthState } from '../../contexts';
export interface PrivateRouteProps extends RouteProps {
redirectPath: string;
}
export const PrivateRoute = ({ redirectPath, ...props }: PrivateRouteProps) => {
const { user } = useAuthState();
if (!user) {
return <Navigate to={redirectPath} />;
}
return <Route {...props} />;
};
useAuthState
是一个钩子,可以在用户登录时检索用户。
我是这样使用它的:
<Routes>
<Route path="/" element={<Home />} />
<PrivateRoute path="/admin" redirectPath="/signin" element={<Admin />} />
<Route path="*" element={<NotFound />} />
</Routes>