拆分複雜度(三):拆分路由

場景

大多數前端開發者在開發應用時,習慣了在一個路由配置文件中大量的引入組件和配置組件,但當路由多了,就會變得不可維護,尤爲在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,或者掃描下面的二維碼

微信號圖片

相關文章
相關標籤/搜索