react通过createBrowserRouter实现的路由定义以及鉴权处理

1,600 阅读2分钟

关于createBrowserRouter

npm install react-router-dom@6.20.0

新版本出现了createBrowserRouter函数,下面我会结合React.Suspenseloader和路由鉴权来实现一个基本的路由,主要功能是

  1. 在加载整个页面之前先查看有没有在本地存储token,然后发请求验证,并且实现自动登录
  2. 在没有登录的状态下(redux仓库里面没有存储登录信息),但是本地存储里面有token(可能是错误的token),我进入某个需要鉴权的页面,发送验证登录请求
  3. 在发送验证登录请求时,用户会发生卡顿,响应到达之后,用户无法看见鉴权页面,而是用Loading页面替代,等页面加载完成之后,显示页面(也就是说,用户无法在不登录的情况下看见鉴权页面,但是有一段时间的卡顿,不知道如何解决?)

使用

  • 首先,在index.js中导入路由
import router from './router-config/Routes';
​
// 自动登录逻辑...const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <RouterProvider router={router}></RouterProvider>
);

这好像很奇怪,为什么没有<App />了,那是因为我们把<App />也写到了定义的路由里面

我们只要在<App />里面通过<Outlet />来控制位置即可

  • 下面是路由的定义

loader函数里面返回一个数据,可以在响应的组件里面使用useLoaderData()来接收返回值

const loader = async () => {
    // 可以先在 redux 里面看看是否存储了 用户信息,如果存在用户信息则不需要发请求,直接返回 null
    let resp = (await login()).data
    if (!resp) {
        return redirect("/home")
    }
    localStorage.setItem("token", resp)
    return resp
}
​
const LazyLoad = ({ ReactFn }) => {
    return (
        <>
            <Suspense fallback={<Loader />}>
                {<ReactFn />}
            </Suspense>
        </>
    )
}
​
export default createBrowserRouter([
    {
        path: '/',
        element: <App />,
        children: [
            {
                path: '',
                element: <RouteBefore />,
                children: [
                    {
                        path: '/',
                        element: <Navigate replace to="/home" />
                    },
                    {
                        path: '/home',
                        element: Home
                    },
                    {
                        path: '/myself',
                        loader: loader,
                        element: <LazyLoad ReactFn={MySelf} />
                    }
                ]
            }
        ]
    }
])
  • 下面是关于路由拦截器
const RouteBeforeConfig = [
    {path: '/home', needLogin: false},
    {path: '/myself', needLogin: true},
    {path: /^/about.*/, needLogin: false}
]
​
export default function RouteBefore() {
    const location = useLocation()
    const navigate = useNavigate()
    const curPath = RouteBeforeConfig.find(it => {
        if(typeof it.path === "string") {
            return it.path === location.pathname
        }
        if(it.path instanceof RegExp) {
            return it.path.test(location.pathname)
        }
    }) // 这里的 RouteBeforeConfig 定义了所有的路由跳转是否需要鉴权
    let token = localStorage.getItem("token")
    if(curPath?.needLogin && !token) {
        navigate('/home')
        alert("未登录!")
    }else {
        return (
            <>
                <Outlet />
            </>
        )
    }
}
  • 对于自动登录可以在main.js中发送,然后再保存到仓库里面