如何在React中动态添加路由组件

// 高阶组件,封装过的  router.js
import asyncComponent from "../utils/asyncComponent";  // 这个后面会有讲解

import BasicLayout from "../layout/BasicLayout";
import NotFount from '../components/NotFount'

const CallBack = asyncComponent(() => import('../pages/javascript/CallBack'))
const Closure = asyncComponent(() => import('../pages/javascript/Closure'))

const router = [
  {
    path: '/',
    redirect: '/tool/content'
  },
  {
    path: '/tool',
    component: BasicLayout,
    routes: [
      {
        path: '/javascript',
        name: 'JS高级',
        component: NotFount,
        routes: [
          {
            path: '/fn',
            name: '函数借调',
            component: CallBack
          },
          {
            path: '/closure',
            name: '闭包',
            component: Closure
          }
        ]
      }
    ]
  }
]

处理路由文件,作为react中的每个组件

import { Route, Redirect } from 'react-router-dom'

export function routeWithSub(router, fatherPath, list) {
  router.forEach(item => {
  	// 拼接路由路径
    let path = fatherPath + item.path
    item.path && item.component && list.push(<Route exact key={ path } path={ path } render={ props => ( <item.component { ...props } routes={item.routes ? item.routes : []} content={list} /> ) } />)
    if (item.routes) {
      routeWithSub(item.routes, path, list)
    }
  })
}

// 此处传入的就是 routejs 路由
export function withRoute(router) {
  let routerList = [] // 父组件路由
  let list = [] // 所有的子组件的路由
  router.forEach(item => {
    let path = item.path
    // 如果存在子路由交给递归继续处理
    if (item.routes) {
      routeWithSub(item.routes, path, list)
      // 父组件直接push 
      routerList.push(
        <Route key={ path } path={ path } render={ props => (
          <item.component {...props} routes={ item.routes } content={ list } />
        )} /> 
      )
    } else if (item.redirect) {
      routerList.push( <Redirect exact={ true } key={ item.path } from={ item.path } to={ item.redirect } /> )
    }
  })
  return routerList
}

直接在App.js 中引入这两个文件

import React from 'react'
import { HashRouter as Router, Switch } from 'react-router-dom'
import { withRoute } from './utils/route'

import router from './router/index'

export default class App extends React.Component {  
  render() {
    const routerList = withRoute(router)
    return (
        <Router>
          <Switch>
            { routerList }
          </Switch>
        </Router>
    )
  }

}

直接可以使用router.js 渲染路由菜单 如图

在这里插入图片描述

最后附上关于一个高阶函数,引入加载nprogress

  • asyncComponent.js
import React from 'react'
import nprogress from 'nprogress'
import 'nprogress/nprogress.css'

/**
 * 从加载时到加载结束用nprogress
 * @param {*} importComponent 传入的组件
 * @returns 高阶组件封装过的
 * 
 */

export default function asyncComponent(importComponent) {
  class AsyncComponent extends React.Component {
    constructor(props) {
      super(props)
      // 开始加载
      nprogress.start()
      this.state = {
        component: null
      }
    }
    
    async componentDidMount() {
      // Es6 解构赋值 先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
      const { default: component } = await importComponent() 
      // 加载完成
      nprogress.done()
      this.setState({
        component: component
      })
    }
    
    render() {
      const C = this.state.component
      return C ? <C { ...this.props }></C> : null
    }
  }
  return AsyncComponent
}

如有问题,欢迎吐槽,共同学习,共同进步。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐