详解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 相关文章推荐
JavaScript中Math对象使用说明
Jan 16 Javascript
用JS实现一个页面多个css样式实现
May 29 Javascript
JS 面向对象的5钟写法
Jul 31 Javascript
jQuery判断元素上是否绑定了指定事件的方法
Mar 17 Javascript
jQuery+HTML5实现图片上传前预览效果
Aug 20 Javascript
zepto中使用swipe.js制作轮播图附swipeUp,swipeDown不起效果问题
Aug 27 Javascript
jquery实现倒计时功能
Dec 28 Javascript
Bootstrap3 多个模态对话框无法显示的解决方案
Feb 23 Javascript
详解Angular中实现自定义组件的双向绑定的两种方法
Nov 23 Javascript
详解用场景去理解函数柯里化(入门篇)
Apr 11 Javascript
js模拟实现百度搜索
Jun 28 Javascript
Nest.js散列与加密实例详解
Feb 24 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文件打包下载zip
2017/03/01 PHP
PHP使用SWOOLE扩展实现定时同步 MySQL 数据
2017/04/09 PHP
a标签的href和onclick 的事件的区别介绍
2013/07/26 Javascript
JS 屏蔽键盘不可用与鼠标右键不可用的方法
2013/11/18 Javascript
深入探寻seajs的模块化与加载方式
2015/04/14 Javascript
跟我学习javascript的arguments对象
2015/11/16 Javascript
js滑动提示效果代码分享
2016/03/10 Javascript
js简单判断flash是否加载完成的方法
2016/06/21 Javascript
浅谈Angular中ngModel的$render
2016/10/24 Javascript
JS实现按钮控制计时开始和停止功能
2017/07/27 Javascript
详解Vue webapp项目通过HBulider打包原生APP(vue+webpack+HBulider)
2019/02/02 Javascript
mpvue微信小程序的接口请求fly全局拦截代码实例
2019/11/13 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
如何在postman测试用例中实现断言过程解析
2020/07/09 Javascript
ant design vue导航菜单与路由配置操作
2020/10/28 Javascript
python遍历 truple list dictionary的几种方法总结
2016/09/11 Python
python检查URL是否正常访问的小技巧
2017/02/25 Python
Python实现将HTML转换成doc格式文件的方法示例
2017/11/20 Python
python 按不同维度求和,最值,均值的实例
2018/06/28 Python
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
2019/03/01 Python
python中对_init_的理解及实例解析
2019/10/11 Python
python调用matplotlib模块绘制柱状图
2019/10/18 Python
详解Python修复遥感影像条带的两种方式
2020/02/23 Python
德国PC硬件网站:CASEKING
2016/10/20 全球购物
Spartoo葡萄牙鞋类网站:线上销售鞋履与时尚配饰
2017/01/11 全球购物
西班牙第一的网上药房:PromoFarma.com
2017/04/17 全球购物
幼儿园老师辞职信
2014/01/20 职场文书
周年庆促销方案
2014/03/15 职场文书
计算机专业自荐信范文
2014/05/28 职场文书
小学生差生评语
2014/12/29 职场文书
晚会开幕词
2015/01/28 职场文书
卡特教练观后感
2015/06/08 职场文书
thinkphp 获取控制器及控制器方法
2021/04/16 PHP
实例讲解Python中sys.argv[]的用法
2021/06/03 Python
使用canvas仿Echarts实现金字塔图的实例代码
2021/11/11 HTML / CSS
python中validators库的使用方法详解
2022/09/23 Python