详解react-router如何实现按需加载

注:本文使用的 react-router 版本为 2.8.1

React Router 是一个非常出色的路由解决方案,同时也非常容易上手。但是当网站规模越来越大的时候,首先出现的问题是 Javascript 文件变得巨大,这导致首页渲染的时间让人难以忍受。实际上程序应当只加载当前渲染页所需的 JavaScript,也就是大家说的“代码分拆" — 将所有的代码分拆成多个小包,在用户浏览过程中按需加载。

所得到的效果是:

以前是这样(23333,我真不是故意的。。)

现在是这样:

实际上就是将一个大 javascript 文件拆分成了若干个 chunk file。

下面是改造过程

Webpack 配置

首先在 webpack.config.js output 内加上 chunkFilename

output: {
  path: path.join(__dirname, '/../dist/assets'),
  filename: 'app.js',
  publicPath: defaultSettings.publicPath,
  // 添加 chunkFilename
  chunkFilename: '[name].[chunkhash:5].chunk.js',
},

name 是在代码里为创建的 chunk 指定的名字,如果代码中没指定则 webpack 默认分配 id 作为 name。

chunkhash 是文件的 hash 码,这里只使用前五位。

添加首页

以前你的路由大概应该是这样的:(作为需要按需加载的大型应用,路由肯定是相当复杂,这里只列举部分路由举例)

ReactDOM.render(
 (
  <Router history={browserHistory}>
   {/* 主页 */}
   <Route path="/" component={App}>
    {/* 默认 */}
    <IndexRoute component={HomePage} />

    {/* baidu */}
    <Route path="/baidu" component={BaiduPage}>
     <Route path="result" component={BaiduResultPage} />
     <Route path="frequency" component={BaiduFrequencyPage} />
    </Route>

    {/* 404 */}
    <Route path='/404' component={NotFoundPage} />

    {/* 其他重定向到 404 */}
    <Redirect from='*' to='/404' />
   </Route>
  </Router>
 ), document.getElementById('app')
);

按需加载之后,我们需要让路由动态加载组件,需要将 component 换成 getComponent。首先将路由拆出来(因为路由庞大之后全部写在一起会很难看),创建一个根路由 rootRoute:

const rootRoute = {
 path: '/',
 indexRoute: {
  getComponent(nextState, cb) {
   require.ensure([], (require) => {
    cb(null, require('components/layer/HomePage'))
   }, 'HomePage')
  },
 },
 getComponent(nextState, cb) {
  require.ensure([], (require) => {
   cb(null, require('components/Main'))
  }, 'Main')
 },
 childRoutes: [
  require('./routes/baidu'),
  require('./routes/404'),
  require('./routes/redirect')
 ]
}

ReactDOM.render(
 (
  <Router
   history={browserHistory}
   routes={rootRoute}
   />
 ), document.getElementById('app')
);

history 不变,在 Router 中添加 routes 属性,将创建的路由传递进去。

这里有四个属性:

path

将匹配的路由,也就是以前的 path。

getComponent

对应于以前的 component 属性,但是这个方法是异步的,也就是当路由匹配时,才会调用这个方法。

这里面有个 require.ensure 方法

require.ensure(dependencies, callback, chunkName)

这是 webpack 提供的方法,这也是按需加载的核心方法。第一个参数是依赖,第二个是回调函数,第三个就是上面提到的 chunkName,用来指定这个 chunk file 的 name。

如果需要返回多个子组件,则使用 getComponents 方法,将多个组件作为一个对象的属性通过 cb 返回出去即可。这个在官方示例也有,但是我们这里并不需要,而且根组件是不能返回多个子组件的,所以使用 getComponent。

indexRoute

用来设置主页,对应于以前的 <IndexRoute>。

注意这里的 indexRoute 写法, 这是个对象,在对象里面使用 getComponent。

childRoutes

这里面放置的就是子路由的配置,对应于以前的子路由们。我们将以前的 /baidu、/404 和 * 都拆了出来,接下来将分别为他们创建路由配置。

路由控制

上面的childRoutes 里面,我们 require 了三个子路由,在目录下创建 routes 目录,将这三个路由放置进去。

routes/
├── 404
│  └── index.js
├── baidu
│  ├── index.js
│  └── routes
│    ├── frequency
│    │  └── index.js
│    └── result
│      └── index.js
└── redirect
  └── index.js

和 rootRoute 类似,里面的每个 index.js 都是一个路由对象:

/404/index.js

module.exports = {
 path: '404',

 getComponent(nextState, cb) {
  require.ensure([], (require) => {
   cb(null, require('components/layer/NotFoundPage'))
  }, 'NotFoundPage')
 }
}

/baidu/index.js

module.exports = {
 path: 'baidu',

 getChildRoutes(partialNextState, cb) {
  require.ensure([], (require) => {
   cb(null, [
    require('./routes/result'),
    require('./routes/frequency')
   ])
  })
 },

 getComponent(nextState, cb) {
  require.ensure([], (require) => {
   cb(null, require('components/layer/BaiduPage'))
  }, 'BaiduPage')
 }
}

/baidu/routes/frequency/index.js

module.exports = {
 path: 'frequency',

 getComponent(nextState, cb) {
  require.ensure([], (require) => {
   cb(null, require('components/layer/BaiduFrequencyPage'))
  }, 'BaiduFrequencyPage')
 }
}

举这几个例子应该就差不多了,其他都是一样的,稍微有点特别的是 redirect。

设置 Redirect

之前我们在根路由下是这么设置重定向的:

<Router history={browserHistory}>
   <Route path="/" component={App}>
    {/* home */}
    <IndexRoute component={HomePage} />

    <Route path="/baidu" component={BaiduPage}>
     <Route path="result" component={BaiduResultPage} />
     <Route path="frequency" component={BaiduFrequencyPage} />
    </Route>

    <Route path='/404' component={NotFoundPage} />
    {/* 如果都不匹配,重定向到 404 */}
    <Redirect from='*' to='/404' />
   </Route>
  </Router>

当改写之后,我们需要把这个重定向的路由单独拆出来,也就是 * 这个路由,我们上面已经为他创建了一个 redirect 目录。这里使用到 onEnter 方法,然后在这个方法里改变路由状态,调到另外的路由,实现 redirect :

/redirect/index.js

module.exports = {
 path: '*',
 onEnter: (_, replaceState) => replaceState(null, "/404")
}

The root route must render a single element

跟着官方示例和上面码出来之后,可能页面并没有渲染出来,而是报 The root route must render a single element 这个异常,这是因为 module.exports 和 ES6 里的 export default 有区别。

如果你是使用 es6 的写法,也就是你的组件都是通过 export default 导出的,那么在 getComponent 方法里面需要加入 .default。

getComponent(nextState, cb) {
  require.ensure([], (require) => {
   // 在后面加 .default
   cb(null, require('components/layer/ReportPage')).default
  }, 'ReportPage')
}

如果你是使用 CommonJS 的写法,也就是通过 module.exports 导出的,那就无须加 .default 了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • React-router中结合webpack实现按需加载实例

    简要介绍:在React-router中,暴露了3个接口,如果结合webpack的code splitting,就通过切换路由实现按需加载. 1.webpack的code splitting webpack可以通过一些方法,来实现按需加载,暴露的接口为require.ensure require.ensure(["module-a", "module-b"], function() { var a = require("module-a"); //

  • React-router 4 按需加载的实现方式及原理详解

    React-router 4 介绍了在router4以后,如何去实现按需加载Component,在router4以前,我们是使用getComponent的的方式来实现按需加载的,router4中,getComponent方法已经被移除,下面就介绍一下react-router4是入围和来实现按需加载的. 1.router3的按需加载方式 route3中实现按需加载只需要按照下面代码的方式实现就可以了. const about = (location, cb) => { require.ensure

  • react-router实现按需加载

    本文使用的 React-router 版本为 2.8.1 React Router自己就有一套按需加载解决方案,将代码拆分成多个小包,在浏览过程中实现按需加载: 如过你的项目搭配了webpack打包工具,那么需要在webpack.config.js的output内加上chunkFilename output: { path: path.join(__dirname, '/../dist/assets'), filename: 'app.js', publicPath: defaultSettin

  • 详解vue项目优化之按需加载组件-使用webpack require.ensure

    使用 vue-cli构建的项目,在 默认情况下 ,执行 npm run build  会将所有的js代码打包为一个整体, 打包位置是 dist/static/js/app.[contenthash].js 类似下面的路由代码 router/index.js  路由相关信息,该路由文件引入了多个 .vue组件 import Hello from '@/components/Hello' import Province from '@/components/Province' import Segm

  • 基于vue和react的spa进行按需加载的实现方法

    基于vue和react的spa进行按需加载 由于最近打算将所有的管理系统采用同一套登陆方法,然后在登陆后进行系统的切换选择,不需要每个系统都去重新登陆一次,所以前端这边思考将所有的系统用一套spa的应用进行构建,但是各个系统的合并之后,打包后的代码应该是相当大的,单页需要一次性加载所有系统的资源,显得不合实际,所以打算将不同系统的资源进行分离,再选择后在加载该系统的相应资源.自己发现这个业务和每个系统的路由比较类似,因此将系统的配置基于vue-router或者react-router的基础进行按

  • react中路由和按需加载的问题

    目录 react路由和按需加载问题 1 基本的路由设置 2 如何完成路由的菜单部分 3 如何将每个路由的js文件分开输出 4 react-router按需加载配置 5 最后效果 react路由的基本使用 1.先下包 2.导入并使用 3.使用HashRouter包裹整个应用 4.使用Link指定导航链接 5.使用Route指定路由规则(哪个路径展示哪个组件) 6.精确匹配 :exact 7.Switch 8.处理404页 Redirect react路由和按需加载问题 1 基本的路由设置 reac

  • 详解vue2路由vue-router配置(懒加载)

    vue路由配置以及按需加载模块配置 1.首先在component文件目录下写俩组件: First.vue: <template> <div>我是第一个页面</div> </template> <script> export default { name: 'first', data () { return { msg: 'Welcome to Your Vue.js App' } } } </script> <!-- Add &

  • 详解AngularJs路由之Ui-router-resolve(预加载)

    ng-route模块中的when()和ui-route的state()都提供了resolve属性. 为什么需要使用resolve? 当路由切换的时候,被路由的页面中的元素(标签)就会立马显示出来,同时,数据会被准备好并呈现出来.但是注意,数据和元素并不是同步的,在没有任何设置的情况下,AngularJS默认先呈现出元素,而后再呈现出数据.这样就会导致页面会被渲染两遍,导致"页面UI抖动"的问题,对用户不太友好.resolve的出现解决了这个问题. resolve是干嘛用的 resolv

  • 详解使用Vue.Js结合Jquery Ajax加载数据的两种方式

    整理文档,搜刮出一个使用Vue.Js结合Jquery Ajax加载数据的两种方式的代码,稍微整理精简一下做下分享. 废话不多说,直接上代码 html代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>demo</title> <script src="js/jquery.js"

  • 详解VUE的状态控制与延时加载刷新

    在实际项目中,我们经常会遇到这种状况,某些数据我们希望等到需要的时候再去获取,或者某些数据我们需要刷新,但是不必立刻刷新,而是延时到展示的时候再去刷新. 在DOM操作的年代,想要实现这样的功能可能会稍微麻烦一些,然而当我们使用数据驱动的mv*框架的时候,这个想要实现这个需求就容易了许多. 当我们理解数据驱动时,我们很容易想到将需要刷新的状态也设置成为某个数据,在需要刷新的地方watch这个数据,当刷新状态发生变动的时候,watch生效并执行刷新的方法,这就实现了延时刷新.而且我们不再需要关注延时

  • 详解Android的Socket通信、List加载更多、Spinner下拉列表

    Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信.通过建立socket连接,可为通

  • 详解Java中log4j.properties配置与加载应用

    log4j.properties总结: 一.介绍 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务 器.NT的事件记录器.UNIX Syslog守护进程等:我们也可以控制每一条日志的输出格式:通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程. Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式.日志信息的优先级从高到低有ERROR.WARN. I

  • 详解React开发中使用require.ensure()按需加载ES6组件

    首先介绍下动态加载函数: require.ensure([], (require)=>{ let A = require('./a.js').default; }) 如果想要动态加载出es6代码组件,直接require一个es6风格的组件是不行的,因为一般的语言编译工具(如babel),不支持直接require一个es6风格的组件. 那么有种办法可以解决:在es6方式书写的组件底部增加一句:module.exports = YouclassName; import React, {Compone

随机推荐