react-router-dom v5升级到v6 并进行路由配置改造

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包裹,否则懒加载不生效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值