react react-router 实现路由跳转拦截的登录流程

2,027 阅读2分钟

在各个web系统中,特别是一些购物网站在浏览某些页面不需要用户进行登录便能查看,某些页面需要用户登录后才能查看,结合react和react-router实现流程如下。

react 和 react-router-dom版本

react 18
react-router-dom 6

具体实现思路

将需要登录的页面包裹在一个验证登录的容器内,在容器内进行判断用户是否登录,如果用户已经登录则继续渲染页面,如果没有登录则跳转至登录页面进行登录操作,登录成功后再跳转至相对应的页面。这样既实现了未登录拦截,又实现了目标路由的保存。

具体实现步骤

  1. 在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;
  1. 配置路由配置文件即第一步内的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组件用于渲染子路由