配置路由表及登录态校验
前几天我完成了一个哔哩哔哩的博主视频下的一个react项目,借此项目来巩固学习的知识,这篇文章主要记录我在该项目用到的路由知识
配置路由表
在src下新建一个router
文件夹,在router
文件夹下新建index.js
和router.js
router.js是将将项目中的所有路由引入并制作成一张路由表,在该文件下可以进行组件路由路径配置、组件路由名称配置、组件路由携带属性配置、路由的懒加载配置和路由缓存配置等。
具体配置代码:
// router.js文件
import { lazy } from "react";
import Home from '../views/Home'
import { withKeepAlive } from 'keepalive-react-component';
const routes = [
{
path: '/',
name: 'home',
// 使用"keepalive-react-component"插件实现该页面缓存,即在跳转到其他页面后再次返回不会重新刷新页面,保持原有的滚动位置和数据
component: withKeepAlive(Home, { cacheId: 'home', srcoll: true }),
// 设置组件携带title
meta: {
title: '知乎日报-WebApp'
}
},
{
// params形式路由传参,需要在路由表中提前留好参数位置
path: '/detail/:id',
name: 'name',
component: withKeepAlive(lazy(() => import('../views/Detail')), { cacheId: 'detail', srcoll: true }),
meta: {
title: '新闻详情-知乎日报'
}
},
{
path: '/personal',
name: 'personal',
// 使用 lazy 实现路由懒加载
component: lazy(() => import('../views/Personal')),
meta: {
title: '个人中心-知乎日报'
}
},
// 剩下的配置大同小异,不在展示··········
];
// 暴露路由表
export default routes;
index.js文件是路由的真正配置文件,将router.js文件中导出的路由表使用map动态生成Route路由
// router.js文件
export default function RouterView() {
return (
<Suspense fallback={<Mask visible={true}><DotLoading color="white" /></Mask>}>
<Routes>
{routers.map(item => {
let { name, path } = item;
return <Route key={name} path={path} element={<Element {...item} />} />;
})}
</Routes>
</Suspense>
)
};
- Suspense 是用在路由懒加载中,当路由页面没有渲染出来时,渲染fallback的返回值,fallback中的一般都是一个加载中的动画,用于减少白屏和过渡,提升体验,在这里我使用的是 antd-mobile 插件带的加载效果 Mask,可以自行去官网学习如何使用
- router6 使用关键字 Routes 包在 Route 外,取代了原先5时的 Switch
- 使用 map 循环生成 Route,key关键字是一定需要的,在所有使用到 map 生成的元素都必须要保证 key 值的唯一性
- element=<Element {...item} />是将路由信息传递给自己包装的 Element 组件,可以在 Element 组件中进行一些操作,比如传值,修改页面标题和登录态校验
// Element组件+登录态校验
// 假定 checkList 中的路径是需要进行登录态校验的,该方法用于判断是否需要进行登录态校验操作
const isCheckLogin = (path) => {
// 从redux中获取登录信息,base中存放了登录信息
let { base: { info } } = store.getState(),
checkList = ['/personal', '/store', '/update'];
return !info && checkList.includes(path);
}
const Element = function Element(props) {
// 接收{...item}中传过来的值,这些值其实都是路由表中对象的键值对信息(routes.js中配置的键值对信息),component是要作为组件的,所以需要重命名成首字母大写
let { component: Component, meta, path } = props;
// 调用函数,判断是否需要进行登录态校验,同时控制渲染的是组件还是 loading 效果
let isShow = !isCheckLogin(path);
// 用来更新函数组件
let [_, setRandom] = useState(0);
// 登录态校验 每次状态改变都需要判断是否需要登录态校验,否则只会在初始化时进行登录态校验
useEffect(() => {
if (isShow) return;
// 如果info不存在,跳转的地址是三个中的一个,从服务器异步获取登录者信息,info存放的是登陆者的信息
// 在此处用立即执行函数包 async,如果将 async 写在函数 function 处,将会返回一个 Promise 对象,该组件是用作渲染其他组件的,返回值必须为 jsx 不能为Promise
(async () => {
// 调用redux中的函数,从给定的接口中获取登录信息
let infoAction = await actions.base.queryUserInfoAsync();
let info = infoAction.info;
if (!info) {
// 获取后还是不存在,那么就是没有登陆,进行提示登录
Toast.show({
icon: 'fail',
content: '请先登录'
})
// 跳转到登录页,replace 是在登陆组件时需要用到的,其实就是登录界面的返回前一个界面的功能问题
navigate({
pathname: '/login',
search: `?to=${path}`
}, { replace: true })
return;
}
// 获取了信息,说明是登陆状态,派发任务把信息存储到容器中
store.dispatch(infoAction);
// 每次获取完登录信息后都需要更新组件,更新info,从而正确完成登录态校验
setRandom(+new Date());
})();
});
//修改页面的TITLE
let { title = "知乎日报-WebApp" } = meta || {};
document.title = title;
//获取路由信息,基于属性传递给组件
const navigate = useNavigate(),
location = useLocation(),
params = useParams(),
[usp] = useSearchParams();
return (
<>
{
isShow ? <Component
navigate={navigate}
location={location}
params={params}
usp={usp} /> :
<Mask visible={true}>
<DotLoading color="white" />
</Mask>
}
</>
)
};
最后,路由配置完需要在 App 中包裹上相应的插件,例如:BrowserRouter,KeepAliveProvider
import React from "react";
import { BrowserRouter } from 'react-router-dom';
import RouterView from "./router";
import { KeepAliveProvider } from "keepalive-react-component/lib";
const App = function App() {
return (
<BrowserRouter>
<KeepAliveProvider>
<RouterView />
</KeepAliveProvider >
</BrowserRouter>
)
}
export default App;