拆分复杂度(三):拆分路由

场景

大多数前端开发者在开发应用时,习惯了在一个路由配置文件中大量的引入组件和配置组件,但当路由多了,就会变得不可维护,尤为在pc端比较明显,可能涉及到10+的业务模块,每一个业务模块都涉及了3-5个路由地址,甚至更多。所以按照业务拆分路由是咱们下降复杂度的必然方式。

备注:本文分享的是你的router使用的为react-router这个库,版本3.2.1javascript

原来的版本

缺点:当分业务以后,每一个业务都有不少子路由,而且由于对应的组件通常都是不一样的,要都维护在一个文件中,文件会比较大,不方便对应和查看。前端

function RouterConfig() {
  return (
    <Router history={hashHistory}>
      <Route path="login" component={Login} />
      <Route path="/" component={Main}>
        <IndexRoute component={ApplyList} />
        <Route path="index" component={Index} />
        <Route path="apply-list" component={ApplyList} />
      </Route>
    </Router>
  );
}

export default RouterConfig;

在每一个feature中定义本身的路由

目录结构:src目录下新建routers文件夹java

--src
----routers
------index.js
------feature1.js
------feature2.js
------feature3.js
----index.jsreact

示意图以下:git

image.png

拆分以后的顶级路由 

返回一个标准的json结构的路由对象,除了标准的path,component,你还能够加入一些其余想加的属性,用于应用的功能加强,好比name用于显示这一级的页面路由名称,icon用于这个路由的图标标识,meta用于记录一些路由的元信息等。github

import Main from '../layout/main';
import ApplyList from '../pages/applyList';

const Span = () => <span>345345</span>;

export default {
  path: '/feature1',
  name: 'feature1',
  component: Main,
  childRoutes: [
    {
      path: '1',
      name: '1',
      component: ApplyList,
      childRoutes: [{
        path: 'feature1',
        name: 'feature1sdf',
        component: Span,
      }],
    },
    { path: '2', name: '2', component: ApplyList },

  ],

};

备注:有子路由的组件,注意如下三点:
1 父组件的路径不能单独访问,除非设置重定向
2 父组件中设置{this.props.children},子组件的路由将在这个位置展现
3 代码中的组件每一层均可以增长嵌套childRoutes实现无限的子路由地址json

主文件--index.js

这样,在咱们的主文件中,就须要引入拆分以后的各个子路由。而后写一个解析json配置生成route的方法。segmentfault

import React from 'react';
import { hashHistory, Router, Route } from 'react-router';
import feature1 from './feature1';
import feature2 from './feature2';
import feature3 from './feature3';

const combineRoutes = [feature1, feature2, feature3];

function renderRouterV3(routes, contextPath) {
  const children = [];
  const renderRouter = (item, itemContextPath) => {
    let newContextPath;
    if (/^\//.test(item.path)) {
      newContextPath = item.path;
    } else {
      newContextPath = `${itemContextPath}/${item.path}`;
    }
    newContextPath = newContextPath.replace(/\/+/, '/');
    if (item.component && item.childRoutes) {
      const childRoutes = renderRouterV3(item.childRoutes, newContextPath);
      children.push(<Route
              key={newContextPath}
              component={item.component}
            >{childRoutes}
                          </Route>);
    } else if (item.component) {
      children.push(<Route key={newContextPath}
                      component={item.component} path={newContextPath} />);
    }
  };
  routes.forEach(route => {
    renderRouter(route, contextPath);
  });
  return children;
}


function RouterConfig() {
  return <Router history={hashHistory}>
      {renderRouterV3(combineRoutes, '/')}
           </Router>;
}

export default RouterConfig;

解析:renderRouterV3 是我本身封装的一个方法,和开源库react-router-config实现的效果是一致的,基于json结构的路由配置能够实现生成对应的router配置。优势在于减小库依赖,灵活性更强,能够针对本身的需求在路由的生成以及自定义渲染上增长更多内容。数组

renderRouterV3的核心逻辑是:
0 内部定义一个渲染单组件方法,renderRouter,传入当前的单组件以及相对路径
1 解析一个传入的顶级路由数组
2 针对每一项,调用renderRouter
3 renderRouter内部针对每一个顶级路由数组解析它的结构,若是是纯组件,直接返回router对象也是停止条件;若是发现其具备childRoutes,那么调用renderRouterV3自己,实现递归
4 方法返回生成后的route数组做为router组件的子组件

react-router-config

可能会有小伙伴问为何不直接用react-router-config这个库呢?缘由有:微信

1 这个库其实有特定的react-router的版本依赖,但你的项目很是可能不是这个版本。那么就会致使两个方向的思考:是换react-router的版本么?但这样会致使项目中有些组件不能用了,好比<Link>;若是不换呢,这个库就不能用,报错须要的Switch组件没有。

2 其实就结果来看,这个根据json生成<Router>的功能也比较简单,本身实现也是没有难度的,并且还能够追加本身想要的其余功能,由于咱们在每一个route中均可以根据传入的对象的某些属性自定义render,这位应用的强化和自定义留下了更多空间。

3 若是有时间,折腾下也何尝不可,不要总想着有什么需求就去找第三方库。其实相似classname这样的库,咱们不必定须要。尤为在特别简单的class管理的时候。

小结

经过本文但愿你能了解想拆分路由复杂度时,能够作的事情,以及如何自定义。

关于我

我是一名前端Coder,热爱分享生活与技术中的经验与心得。
我是一名旅游爱好者,爱好拍摄旅途中的风景与人物。
我是一名写做狂人,基本天天都有新文章产出,笔耕不辍。

我的站点

GitHub:http://github.com/robinson90
codepen:https://codepen.io/robinson90
personal blog: http://damobing.com
yuque docs: https://www.yuque.com/robinson
juejin blog: https://juejin.im/user/5a30ce...

我的微信号与公众号

微信:csnikey,或者扫码加我
微信号图片

达摩空间订阅号:damo_kongjian,或者扫描下面的二维码

微信号图片

相关文章
相关标签/搜索