v5到v6升级概括
- Switch 组件替换为 Routes 组件。
- 如何放置 Route 的渲染组件。
- render替换为element
- 路由中没有exact。
- activeClassName和activeStyle不存在于NavLink组件了。
- 可以通过函数回调访问 NavLink 组件的 isActive 状态
- Redirect组件替换为Navigate组件。
- 没有Prompt组件
目标
基于统一的路由配置进行路由加载,并进行统一逻辑处理,比如菜单渲染,页面鉴权等,同时实现组件的按需加载,当需要新增和编辑路由时,只需要修改[自定义路由配置]文件即可
自定义路由配置结构说明
- path 页面路径
- component 对应渲染组件
- beforeEnter 渲染组件前的逻辑处理
- menu 菜单属性,包括标签title和响应式布局等设置
- children 嵌套子路由
注意:当存在子路由时,不要设置component属性,否则子组件可能不会被渲染
路由配置示例
- route/const.js
import { userInfo } from '../service/common';
import CreateActivity from '../component/ActivityManage/ActivityList/CreateActivity';
import ActivityDetail from '../component/ActivityManage/ActivityList/ActivityDetail';
import ActivityPanel from '../component/ActivityManage/ActivityPanel';
import Durables from '../entry/Durables';
import ActivityManage from '../entry/ActivityManage';
const routes = [
{
path: '/',
beforeEnter: userInfo,
children: [
{
path: 'activity',
children: [
{
path: 'list',
children: [
{
path: ':panelId',
component: ActivityPanel
},
{
index: true,
component: ActivityManage
},
{
path: 'create',
component: CreateActivity
},
{
path: 'edit/:activityId',
component: CreateActivity
},
{
path: 'detail/:activityId',
component: ActivityDetail
}
]
}
]
},
{
path: 'durables',
component: Durables,
menu: {
theme: 'responsive'
}
},
{ path: '*', component: ActivityManage }
]
}
];
export default routes;
根据自定义路由配置进行统一逻辑处理
示例
- route/index.js
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Provider } from 'react-redux';
import routes from './constant';
import store from '../redux/lib/store';
import ErrorBoundary from '../component/Common/ErrorBoundary';
import AsyncComponent from '../component/Common/AsyncComponent';
function getRoutes(rs) {
return rs.map(route => routeWithSubRoutes(route));
}
function routeWithSubRoutes(route) {
const { children, path, ...rest } = route;
if (children && children.length > 0) {
return (
<Route key={path} path={path} {...rest}>
{getRoutes(children)}
</Route>
);
}
return (
<Route
key={path || 'index'}
path={path}
{...rest}
element={<AsyncComponent route={route} />}
/>
);
}
export default function RouteConfig() {
return (
<ErrorBoundary>
<Provider store={store}>
<Router basename="/datadrive/page/">
<Routes>{getRoutes(routes)}</Routes>
</Router>
</Provider>
</ErrorBoundary>
);
}
AsyncComponent组件渲染前逻辑和组件懒加载处理
import React, { Suspense, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import ScreenLoading from '../ScreenLoading';
// import MainLayout from '../MainLayout';
const MainLayout = React.lazy(() =>
import(/* webpackChunkName:"MainLayout" */ '../MainLayout')
);
/**
* 组件懒加载和加载前逻辑处理
* @param props
* @returns {JSX.Element|null}
* @constructor
*/
function AsyncComponent(props) {
const { route } = props;
const AsyncComp = (
<Suspense fallback={<ScreenLoading loading />}>
<MainLayout {...props} />
</Suspense>
);
if (!route.beforeEnter) {
return AsyncComp;
}
// eslint-disable-next-line react-hooks/rules-of-hooks
const [finish, setStatus] = useState(false);
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => {
route
.beforeEnter()
.then(() => {
setStatus(true);
})
.catch(e => {
console.warn(e);
setStatus(true);
});
}, []);
return finish ? AsyncComp : null;
}
AsyncComponent.propTypes = {
route: PropTypes.object.isRequired
};
export default AsyncComponent;
MainLayout进行页面布局和菜单展示等处理
示例
/**
* @param App 入口组件
* @param menu 组件菜单信息 code:菜单标识,name:页面标题
* @param action
* @param initialState
* @returns {JSX.Element}
* @constructor
*/
import React from 'react';
import DMPage from './DMPage';
const MainLayout = props => {
const { route } = props;
const { menu } = route;
const LazyComp = route.component;
return menu?.remove ? (
<LazyComp {...props} />
) : (
<DMPage {...menu}>
<LazyComp {...props} />
</DMPage>
);
};
export default MainLayout;
MainLayout可替换成项目整体布局组件
入口文件中引入路由配置即可
import ReactDOM from 'react-dom';
import './index.scss';
import Routes from '../router';
const route = Routes();
ReactDOM.render(route, document.getElementById('root'));
注意事项
1、当存在子路由时,不要设置component属性,否则子组件可能不会被渲染(会渲染父路由中设置的组件),除非父组件是一个容器组件或者全局布局或菜单组件
2、需要懒加载的组件需要被Suspense进行包裹,不要在最外层设置一个Suspense,需要在每个懒加载组件进行Suspense包裹,否则懒加载不生效