1、下面是使用高阶组件实现路由守卫的示例代码:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => (
<Route
{...rest}
render={(props) =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/login', state: { from: props.location } }} />
)
}
/>
);
export default PrivateRoute;
在上面的代码中,PrivateRoute
是一个高阶组件,它接收一个组件作为参数,并返回一个新的组件。在 render
方法中,如果用户已经登录,则渲染传入的组件;否则,重定向到登录页面。通过使用该高阶组件,我们可以在需要进行权限验证的路由上使用 PrivateRoute
来保护路由,例如:
<Switch>
<PrivateRoute exact path="/" component={Home} isAuthenticated={isAuthenticated} />
<PrivateRoute path="/dashboard" component={Dashboard} isAuthenticated={isAuthenticated} />
<Route path="/login" component={Login} />
</Switch>
其中 isAuthenticated
是一个布尔值,表示当前用户是否已经登录。
2、使用 函数组件或 render 属性来实现路由守卫
React Router 可以使用 Route
组件的 render
属性或函数式组件来实现路由守卫。
使用 render
属性时,可以传入一个函数,根据需要来渲染不同的组件或页面。在这个函数中可以实现路由守卫的逻辑,例如检查用户是否登录,根据用户角色判断是否有权限访问该页面等。如果不满足条件,可以返回一个重定向或提示信息,否则可以渲染目标组件或页面。
示例代码:
import { Route, Redirect } from 'react-router-dom';
function PrivateRoute({ component: Component, isAuth, ...rest }) {
return (
<Route
{...rest}
render={(props) =>
isAuth ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/login',
state: { from: props.location },
}}
/>
)
}
/>
);
}
在上面的示例中,PrivateRoute
组件接受三个参数:component
,代表需要渲染的目标组件;isAuth
,代表用户是否已登录;rest
,代表其他参数,例如路由路径等。在 render
函数中,如果用户已登录,就渲染目标组件,否则返回一个重定向到登录页面。
使用函数式组件时,可以将需要实现路由守卫的逻辑直接写在函数组件中,例如在 useEffect
钩子函数中进行判断。如果不满足条件,可以使用 history.push
方法进行重定向。
import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
function PrivatePage() {
const history = useHistory();
const isAuth = true;
useEffect(() => {
if (!isAuth) {
history.push('/login');
}
}, [isAuth, history]);
return <div>Private Page</div>;
}
在上面的示例中,如果用户未登录,就会使用 history.push
方法将页面重定向到登录页面。这里的 useEffect
钩子函数会在组件渲染完成后执行,也可以根据需要添加其他依赖项。
虽然React没有路由守卫,但是我们可以通过高阶组件实现相关功能,使用方法如下
import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
const allowList = ['/login', '/register'];
const loginRoute = '/login';
const indexRoute = '/'
export default function AuthRoute(props) {
const location = useLocation();
// children 为子组件
const { children } = props;
// 根据 token 对路由进行权限校验,需要和后端配合使用
// 这里的 token 一般是登陆成功之后拿到后端返回的 token 并通过 Cookie.set('token', token字符串, {
// expires: time_limit // 设置存放时间
// })设置
let token = false;
if (token && token !== 'undefined') {
// 有 token 的状态下禁止用户回到登录页,重定向到首页
if (location.pathname === loginRoute) {
return <Navigate to={indexRoute}></Navigate>;
} else {
// 其他路由均可正常跳转
return <>{children}</>;
}
} else {
// 无 token 的状态下,如果要跳转的路由是白名单中的路由,正常跳转
if (allowList.includes(location.pathname || '')) {
return <>{children}</>;
} else {
// 无 token 且非白名单路由,重定向至登录页
return <Navigate to={loginRoute}></Navigate>;
}
}
}
//https://zhuanlan.zhihu.com/p/628935247 React Router 组件路由守卫(Route Guard)的机制
import React from 'react';
import ReactDOM from 'react-dom/client';
import './styles/basic.scss';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import ThemeContext from './store/themeContext';
import store from './store';
import AuthRoute from './auth/auth';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<ThemeContext.Provider
value={{
store
}}
>
<AuthRoute>
<App />
</AuthRoute>
</ThemeContext.Provider>
</BrowserRouter>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();