详解react-router4 异步加载路由两种方法


Posted in Javascript onSeptember 12, 2017

方法一:我们要借助bundle-loader来实现按需加载。

首先,新建一个bundle.js文件:

import React, { Component } from 'react'

export default class Bundle extends React.Component {

  state = {
    // short for "module" but that's a keyword in js, so "mod"
    mod: null
  }

  componentWillMount() {
    this.load(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps)
    }
  }

  load(props) {
    this.setState({
      mod: null
    })
    props.load((mod) => {
      this.setState({
        // handle both es imports and cjs
        mod: mod.default ? mod.default : mod
      })
    })
  }

  render() {
    if (!this.state.mod)
      return false
    return this.props.children(this.state.mod)
  }
}

然后,在入口处使用按需加载:

// ...

// bundle模型用来异步加载组件
import Bundle from './bundle.js';

// 引入单个页面(包括嵌套的子页面)
// 同步引入
import Index from './app/index.js';
// 异步引入
import ListContainer from 'bundle-loader?lazy&name=app-[name]!./app/list.js';

const List = () => (
  <Bundle load={ListContainer}>
    {(List) => <List />}
  </Bundle>
)

// ...

  <HashRouter>
    <Router basename="/">
      <div>
        <Route exact path="/" component={Index} />
        <Route path="/list" component={List} />
      </div>
    </Router>
  </HashRouter>

// ...


webpack.config.js文件配置
output: {
  path: path.resolve(__dirname, './output'),
  filename: '[name].[chunkhash:8].bundle.js',
  chunkFilename: '[name]-[id].[chunkhash:8].bundle.js',
},

方法二:用原生的

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

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

    {/* baidu */}
    <Route path="/baidu"




getComponent(nextState, cb) 





{ require.ensure([], (require) => { cb(null, require('components/layer/HomePage')) }, 'HomePage')}>
     <Route path="result"   getComponent... />
     <Route path="frequency" getComponent... />
    </Route>
    {/* 404 */}
    <Route path='/404' getComponent... />
    {/* 其他重定向到 404 */}
    <Redirect path='*' onEnter: (_, replaceState) => replaceState(null, "/404") />
   </Route>
  </Router>
 ), document.getElementById('app')
);

getComponent

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

这里面有个 require.ensure 方法

require.ensure(dependencies, callback, chunkName)

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

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

当改写之后,我们需要把这个重定向的路由单独拆出来,也就是 * 这个路由,我们上面已经为他创建了一个 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 了。

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

Javascript 相关文章推荐
js中cookie的使用详细分析
May 28 Javascript
很可爱的输入框
Aug 03 Javascript
Javascript Global对象
Aug 13 Javascript
javascript权威指南 学习笔记之javascript数据类型
Sep 24 Javascript
基于jquery打造的百分比动态色彩条插件
Sep 19 Javascript
jQuery编辑器KindEditor4.1.4代码高亮显示设置教程
Mar 01 Javascript
解决iView中时间控件选择的时间总是少一天的问题
Mar 15 Javascript
如何解决.vue文件url引用文件的问题
Jan 18 Javascript
对layui数据表格动态cols(字段)动态变化详解
Oct 25 Javascript
ES6中new Function()语法及应用实例分析
Feb 19 Javascript
详解vuejs中执行npm run dev出现页面cannot GET/问题
Apr 26 Javascript
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
Dec 02 Vue.js
JS+canvas绘制的动态机械表动画效果
Sep 12 #Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
Sep 12 #Javascript
Angular 4.0学习教程之架构详解
Sep 12 #Javascript
jQuery+vue.js实现的九宫格拼图游戏完整实例【附源码下载】
Sep 12 #jQuery
详解vue axios中文文档
Sep 12 #Javascript
javascript算法之二叉搜索树的示例代码
Sep 12 #Javascript
vue-resouce设置请求头的三种方法
Sep 12 #Javascript
You might like
php中的strpos使用示例
2014/02/27 PHP
PHP实现把文本中的URL转换为链接的auolink()函数分享
2014/07/29 PHP
PHP获取不了React Native Fecth参数的解决办法
2016/08/26 PHP
thinkphp的dump函数无输出实例代码
2016/11/15 PHP
浅谈PHP中new self()和new static()的区别
2017/08/11 PHP
实现超用户体验 table排序javascript实现代码
2009/06/22 Javascript
JQuery中的$.getJSON 使用说明
2011/03/10 Javascript
JS实现定时页面弹出类似QQ新闻的提示框
2013/11/07 Javascript
js模仿hover的具体实现代码
2013/12/30 Javascript
javascript浏览器兼容教程之事件处理
2014/06/09 Javascript
jquery提示效果实例分析
2014/11/25 Javascript
JavaScript开发Chrome浏览器扩展程序UI的教程
2016/05/16 Javascript
Express之get,pos请求参数的获取
2017/05/02 Javascript
浅谈vue方法内的方法使用this的问题
2018/09/15 Javascript
详解Puppeteer前端自动化测试实践
2019/02/21 Javascript
简单了解vue 插值表达式Mustache
2020/07/22 Javascript
[03:52]显微镜下的DOTA2第三期——英雄在无聊的时候干什么
2014/06/20 DOTA
python数据结构之二叉树的统计与转换实例
2014/04/29 Python
单利模式及python实现方式详解
2018/03/20 Python
Python any()函数的使用方法
2019/10/28 Python
python 实现按对象传值
2019/12/26 Python
django 扩展user用户字段inlines方式
2020/03/30 Python
Python3 requests模块如何模仿浏览器及代理
2020/06/15 Python
keras中epoch,batch,loss,val_loss用法说明
2020/07/02 Python
利用纯CSS3实现文字向右循环闪过效果实例(可用于移动端)
2017/06/15 HTML / CSS
Puritan’s Pride(普丽普莱)官方网站:美国最大最全的保健品公司之一
2016/10/23 全球购物
数控专业个人求职信范文
2014/02/05 职场文书
我爱我的祖国演讲稿
2014/05/04 职场文书
社区科普工作方案
2014/06/03 职场文书
群众路线教育实践活动的心得体会
2014/09/03 职场文书
停车位租赁协议书
2014/09/24 职场文书
科长个人四风问题整改措施思想汇报
2014/10/13 职场文书
论群众路线学习笔记
2014/11/06 职场文书
2016年父亲节寄语
2015/12/04 职场文书
《活见鬼》教学反思
2016/02/24 职场文书
解决Jenkins集成SonarQube遇到的报错问题
2021/07/15 Java/Android