详解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 相关文章推荐
读jQuery之六 缓存数据功能介绍
Jun 21 Javascript
从阶乘函数对比Javascript和C#的异同
May 31 Javascript
E3 tree 1.6在Firefox下显示问题的修复方法
Jan 30 Javascript
js获取url中的参数且参数为中文时通过js解码
Mar 19 Javascript
Jquery api 速查表分享
Jan 12 Javascript
浅析JS运动
Dec 28 Javascript
jQuery给指定的table动态添加删除行的操作方法
Oct 12 Javascript
JS去除字符串中空格的方法
Feb 14 Javascript
基于JavaScript实现百度搜索框效果
Jun 28 Javascript
vue项目中,main.js,App.vue,index.html的调用方法
Sep 20 Javascript
在vue中使用echarts(折线图的demo,markline用法)
Jul 20 Javascript
JS实现鼠标按下拖拽效果
Jul 23 Javascript
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使用glob函数快速查询指定目录文件的方法
2014/11/15 PHP
为PHP5.4开启Zend OPCode缓存
2014/12/26 PHP
验证坐标在某坐标区域内php代码
2016/10/08 PHP
phpstorm 配置xdebug的示例代码
2019/03/31 PHP
jquery实现文本框鼠标右击无效以及不能输入的代码
2010/11/05 Javascript
选择器中含有空格在使用示例及注意事项
2013/07/31 Javascript
js switch case default 的用法示例介绍
2013/10/23 Javascript
通过Javascript读取本地Excel文件内容的代码示例
2014/04/08 Javascript
JS实现的左侧竖向滑动菜单效果代码
2015/10/19 Javascript
AngularJS基础 ng-list 指令详解及示例代码
2016/08/02 Javascript
JQuery搜索框自动补全(模糊匹配)功能实现示例
2019/01/08 jQuery
微信小程序学习笔记之表单提交与PHP后台数据交互处理图文详解
2019/03/28 Javascript
Vue代码整洁之去重方法整理
2019/08/06 Javascript
js实现橱窗展示效果
2020/01/11 Javascript
简介Django中内置的一些中间件
2015/07/24 Python
使用简单工厂模式来进行Python的设计模式编程
2016/03/01 Python
把csv文件转化为数组及数组的切片方法
2018/07/04 Python
Python3对称加密算法AES、DES3实例详解
2018/12/06 Python
flask的orm框架SQLAlchemy查询实现解析
2019/12/12 Python
python实现的Iou与Giou代码
2020/01/18 Python
如何使用pandas读取txt文件中指定的列(有无标题)
2020/03/05 Python
在pycharm中使用matplotlib.pyplot 绘图时报错的解决
2020/06/01 Python
python中wheel的用法整理
2020/06/15 Python
安装并免费使用Pycharm专业版(学生/教师)
2020/09/24 Python
澳大利亚在线购买儿童玩具:Toy Universe
2017/12/28 全球购物
女装和独特珠宝:Sundance Catalog
2018/09/19 全球购物
监理资料员岗位职责
2014/01/03 职场文书
数控个人求职信范文
2014/02/03 职场文书
养牛场项目建议书
2014/05/13 职场文书
董事长助理工作职责范本
2014/07/01 职场文书
基层领导干部“四风”问题批评与自我批评
2014/09/23 职场文书
房屋产权共有协议书范本
2014/11/03 职场文书
大学生暑期实践报告之企业经营管理
2019/08/08 职场文书
MySQL中in和exists区别详解
2021/06/03 MySQL
Spring Boot 使用 Spring-Retry 进行重试框架
2022/04/24 Java/Android
python 学习GCN图卷积神经网络
2022/05/11 Python