详解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 相关文章推荐
获取css样式表内样式的js函数currentStyle(IE),defaultView(FF)
Feb 14 Javascript
基于jquery的设置页面文本框 只能输入数字的实现代码
Apr 19 Javascript
通过隐藏iframe实现文件下载的js方法介绍
Feb 26 Javascript
node.js中的fs.fstat方法使用说明
Dec 15 Javascript
浅谈Node.js中的定时器
Jun 18 Javascript
javascript类型系统 Window对象学习笔记
Jan 07 Javascript
jQuery简单创建节点的方法
Sep 09 Javascript
jQuery中的100个技巧汇总
Dec 15 Javascript
简单介绍react redux的中间件的使用
Apr 06 Javascript
javascript中的this作用域详解
Jul 15 Javascript
基于原生js实现九宫格算法代码实例
Jul 03 Javascript
使用eslint和githooks统一前端风格的技巧
Jul 29 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+JS无限级可伸缩菜单详解(简单易懂)
2007/01/02 PHP
详谈PHP编码转换问题
2015/07/28 PHP
微信公众号之主动给用户发送消息功能
2019/06/22 PHP
jQuery 回调函数(callback)的使用和基础
2015/02/26 Javascript
jQuery Mobile中的button按钮组件基础使用教程
2016/05/23 Javascript
js实现小窗口拖拽效果
2016/12/03 Javascript
jQuery控制控件文本的长度的操作方法
2016/12/05 Javascript
任意Json转成无序列表的方法示例
2016/12/09 Javascript
分享一个精简的vue.js 图片lazyload插件实例
2017/03/13 Javascript
js登录滑动验证的实现(不滑动无法登陆)
2018/01/03 Javascript
Node.JS段点续传:Nginx配置文件分段下载功能的实现方法
2018/03/12 Javascript
详解vue组件开发脚手架
2018/06/15 Javascript
vue.js配合$.post从后台获取数据简单demo分享
2018/08/11 Javascript
浅谈webpack性能榨汁机(打包速度优化)
2019/01/09 Javascript
layui自己添加图片按钮并点击跳转页面的例子
2019/09/14 Javascript
[02:44]2014DOTA2 国际邀请赛中国区预选赛 大神红毯秀
2014/05/25 DOTA
[09:59]DOTA2-DPC中国联赛2月7日Recap集锦
2021/03/11 DOTA
Python编程实现及时获取新邮件的方法示例
2017/08/10 Python
python中不能连接超时的问题及解决方法
2018/06/10 Python
python+opencv实现阈值分割
2018/12/26 Python
Python中最大递归深度值的探讨
2019/03/05 Python
python实现贪吃蛇双人大战
2020/04/18 Python
Django Channel实时推送与聊天的示例代码
2020/04/30 Python
浅谈pytorch中的BN层的注意事项
2020/06/23 Python
HTML5注册页面示例代码
2014/03/27 HTML / CSS
英国第二大营养品供应商:Vitabiotics
2016/10/01 全球购物
世界上最大的罕见唱片、CD和音乐纪念品网上商店:991.com
2018/05/03 全球购物
意大利中国电子产品购物网站:Geekmall.com
2019/09/30 全球购物
意大利值得信赖的在线超级药房:PillolaStore
2020/02/05 全球购物
教学大赛获奖感言
2014/01/15 职场文书
2014年社会实践活动总结范文
2014/04/29 职场文书
经济贸易专业自荐信
2014/06/11 职场文书
留学推荐信英文范文
2015/03/26 职场文书
大学考试作弊检讨书
2015/05/06 职场文书
OpenCV-Python实现怀旧滤镜与连环画滤镜
2021/06/09 Python
Python软件包安装的三种常见方法
2022/07/07 Python