在各个web系统中,特别是一些购物网站在浏览某些页面不需要用户进行登录便能查看,某些页面需要用户登录后才能查看,结合react和react-router实现流程如下。
react 和 react-router-dom版本
react 18
react-router-dom 6
具体实现思路
将需要登录的页面包裹在一个验证登录的容器内,在容器内进行判断用户是否登录,如果用户已经登录则继续渲染页面,如果没有登录则跳转至登录页面进行登录操作,登录成功后再跳转至相对应的页面。这样既实现了未登录拦截,又实现了目标路由的保存。
具体实现步骤
- 在app.tsx(应用的入口组件)内注册路由
import { routerConfig } from '@/router';
import { createHashRouter, RouterProvider } from 'react-router-dom';
const router = createHashRouter(routerConfig);
function App() {
return <RouterProvider router={router}></RouterProvider>
}
export default App;
- 配置路由配置文件即第一步内的routerConfig
import { NonIndexRouteObject } from 'react-router-dom';
import RequireAuth from './RequireAuth';
const childrenRoutes = [{
path:'/need-login',
name:'需要登录的页面',
element:<NeedLogin></NeedLogin>
}]
const routerConfig: NonIndexRouteObject[] = [
{
path: '/',
name: '需要登录的路由组',
element: (
<RequireAuth>
<Layout />
</RequireAuth>
),
children: childrenRoutes,
},
{
path: '/other',
element: <Other />,
name: '不需要登录的页面',
},
{
path: '/login',
element: <Login />,
name: '登录',
},
{
path: '/login-error',
element: <LoginError />,
name: '登录异常',
},
];
export { routerConfig };
此时RequireAuth组件相当于跳转到routerConfig内第一个路由以及他所有子路由的拦截器,在RequireAuth内判断是否登录,如果未登录则跳转到登录页面,如果登录了则渲染Layout组件(Layout组件承载了需要登录才能查看页面的的子路由)下面代码为 RequireAuth,Login和Layout实现
RequireAuth实现
import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
const RequireAuth: React.FC<{ children: JSX.Element }> = ({ children }) => {
const location = useLocation();
// 此处代码为简单示例,具体判断方式根据业务需求具体实现,在Login页面登录成功后将此处置为true
if (!window.isLogin) {
return <Navigate to={'/login' + (location.search || '')} state={{ ...(location.state || {}), from: location }}></Navigate>;
}
return children;
};
export default RequireAuth;
引用react-router-dom的Navigate组件,判断没有登录则拦截跳转至登录页面。
Login实现
import { useLocation, useNavigate } from 'react-router-dom';
import { useEffect } from 'react';
export default function Login() {
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
//模拟登录成功
window.isLogin = true;
//跳转至RequireAuth拦截的目标页面
navigate((location.state?.from?.pathname || '/') + (location.search || ''), { state: { ...(location.state || {}) } });
}, []);
return <>{null}</>;
}
Layout实现
import React from 'react';
import { Outlet } from 'react-router-dom';
const Layout: React.FC<unknown> = () => {
return <Outlet />;
};
export default Layout;
此处引用了react-router-dom下的Outlet组件用于渲染子路由