详解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 相关文章推荐
子窗口、父窗口和Silverlight之间的相互调用
Aug 16 Javascript
JS中Iframe之间传值及子页面与父页面应用
Mar 11 Javascript
利用百度地图JSAPI生成h7n9禽流感分布图实现代码
Apr 15 Javascript
js控制表单奇偶行样式的简单方法
Jul 31 Javascript
javascript解析json实例详解
Nov 05 Javascript
jQuery表单对象属性过滤选择器实例详解
Sep 13 Javascript
利用python分析access日志的方法
Oct 26 Javascript
微信小程序 swiper组件构建轮播图的实例
Sep 20 Javascript
vue多级复杂列表展开/折叠及全选/分组全选实现
Nov 05 Javascript
Vue+Element实现动态生成新表单并添加验证功能
May 23 Javascript
通过说明与示例了解js五种设计模式
Jun 17 Javascript
js实现点赞效果
Mar 16 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
全国FM电台频率大全 - 20 广西省
2020/03/11 无线电
收音机的保养
2021/03/01 无线电
PHP实现HTML生成PDF文件的方法
2014/11/07 PHP
php等比例缩放图片及剪切图片代码分享
2016/02/13 PHP
CI框架中$this-&gt;load-&gt;library()用法分析
2016/05/18 PHP
php判断str字符串是否是xml格式数据的方法示例
2017/07/26 PHP
PHP哈希表实现算法原理解析
2020/12/11 PHP
JS实现商品倒计时实现代码
2013/05/03 Javascript
js正文内容高亮效果的实现方法
2013/06/30 Javascript
jQuery实现Twitter的自动文字补齐特效
2014/11/28 Javascript
JS+Canvas实现的俄罗斯方块游戏完整实例
2016/12/12 Javascript
vue.js 左侧二级菜单显示与隐藏切换的实例代码
2017/05/23 Javascript
vue打包后显示空白正确处理方法
2017/11/01 Javascript
vue 2.0 购物车小球抛物线的示例代码
2018/02/01 Javascript
Vue.js项目中管理每个页面的头部标签的两种方法
2018/06/25 Javascript
vue-cli4.x创建企业级项目的方法步骤
2020/06/18 Javascript
解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题
2020/07/27 Javascript
[01:22]DOTA2神秘商店携大量周边降临完美大师赛
2017/11/07 DOTA
为Python程序添加图形化界面的教程
2015/04/29 Python
python实现一个简单的并查集的示例代码
2018/03/19 Python
利用Python将每日一句定时推送至微信的实现方法
2018/08/13 Python
python实现词法分析器
2019/01/31 Python
详解Flask前后端分离项目案例
2020/07/24 Python
python3 googletrans超时报错问题及翻译工具优化方案 附源码
2020/12/23 Python
Python 实现RSA加解密文本文件
2020/12/30 Python
浅谈利用缓存来优化HTML5 Canvas程序的性能
2015/05/12 HTML / CSS
Sephora丝芙兰泰国官方网站:国际知名化妆品购物
2017/11/15 全球购物
学年自我鉴定范文
2013/10/01 职场文书
英文求职信写作小建议
2014/02/16 职场文书
税务干部个人整改措施思想汇报
2014/10/10 职场文书
三严三实学习心得体会
2014/10/13 职场文书
2014年六五普法工作总结
2014/11/25 职场文书
2014年政工师工作总结
2014/12/18 职场文书
公务员考察材料
2014/12/23 职场文书
搞笑的婚礼主持词
2015/06/29 职场文书
2016教师节感恩话语
2015/12/09 职场文书