详解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 相关文章推荐
getElementByIdx_x js自定义getElementById函数
Jan 24 Javascript
jQuery实现点击标题输入详细信息
Apr 16 Javascript
jQuery获取浏览器中的分辨率实现代码
Apr 23 Javascript
用window.onerror捕获并上报Js错误的方法
Jan 27 Javascript
jquery实现点击弹出可放大居中及关闭的对话框(附demo源码下载)
May 10 Javascript
Javascript之Date对象详解
Jun 07 Javascript
用vue快速开发app的脚手架工具
Jun 11 Javascript
vue通过滚动行为实现从列表到详情,返回列表原位置的方法
Aug 31 Javascript
详解关于Vue版本不匹配问题(Vue packages version mismatch)
Sep 17 Javascript
vue-i18n结合Element-ui的配置方法
May 20 Javascript
微信小程序 高德地图路线规划实现过程详解
Aug 05 Javascript
node.js 基于 STMP 协议和 EWS 协议发送邮件
Feb 14 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
电脑硬件及电脑配置知识大全
2020/03/17 数码科技
php文件下载处理方法分析
2015/04/22 PHP
php实现curl模拟ftp上传的方法
2015/07/29 PHP
laravel 使用auth编写登录的方法
2019/09/30 PHP
jQuery.extend 函数的详细用法
2012/06/27 Javascript
extjs tabpanel限制选项卡数量实现思路及代码
2013/04/02 Javascript
返回页面顶部top按钮通过锚点实现(自写)
2013/08/30 Javascript
javascript查找字符串中出现最多的字符和次数的小例子
2013/10/29 Javascript
jquery遍历筛选数组的几种方法和遍历解析json对象
2013/12/13 Javascript
第二章之Bootstrap 页面排版样式
2016/04/25 Javascript
iscroll碰到Select无法选择下拉刷新的解决办法
2016/05/21 Javascript
基于jQuery实现文字打印动态效果
2017/04/21 jQuery
ES6中Math对象新增的方法实例详解
2017/04/25 Javascript
Angular 4.0学习教程之架构详解
2017/09/12 Javascript
js 判断一个数字是不是2的n次方幂的实例
2017/11/26 Javascript
JavaScript设计模式之职责链模式应用示例
2018/08/07 Javascript
vue 根据数组中某一项的值进行排序的方法
2018/08/30 Javascript
详解Vue中的scoped及穿透方法
2019/04/18 Javascript
微信小程序实现单个卡片左滑显示按钮并防止上下滑动干扰功能
2019/12/06 Javascript
Python中bisect的用法
2014/09/23 Python
Python将多个excel文件合并为一个文件
2018/01/03 Python
python3.x 将byte转成字符串的方法
2018/07/17 Python
python如何制作缩略图
2019/04/30 Python
python使用Pandas库提升项目的运行速度过程详解
2019/07/12 Python
对python中的*args与**kwgs的含义与作用详解
2019/08/28 Python
Python3之外部文件调用Django程序操作model等文件实现方式
2020/04/07 Python
德国箱包网上商店:koffer24.de
2016/07/27 全球购物
Mountain Hardwear官网:攀岩服装和户外装备
2019/09/26 全球购物
车间安全生产标语
2014/06/06 职场文书
实验室标语
2014/06/21 职场文书
2014教育局对照检查材料思想汇报
2014/09/23 职场文书
2014年学生党支部工作总结
2014/12/20 职场文书
七一建党节慰问信
2015/02/14 职场文书
干部考核工作总结
2015/08/12 职场文书
学习经验交流会策划书
2015/11/02 职场文书
2016年“我们的节日·重阳节”主题活动总结
2016/04/01 职场文书