详解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 拾色器插件发布-jquery.icolor.js
Oct 20 Javascript
基于Jquery实现的一个图片滚动切换
Jun 21 Javascript
IE6已终止操作问题的2种情况及解决
Apr 23 Javascript
JavaScript设计模式之外观模式实例
Oct 10 Javascript
BootStrap.css 在手机端滑动时右侧出现空白的原因及解决办法
Jun 07 Javascript
JavaScript 链式结构序列化详解
Sep 30 Javascript
JS实现图片点击后出现模态框效果
May 03 Javascript
Javascript 实现匿名递归的实例代码
May 25 Javascript
ES6中javascript实现函数绑定及类的事件绑定功能详解
Nov 08 Javascript
详解Vue.directive 自定义指令
Mar 27 Javascript
JavaScript 实现自己的安卓手机自动化工具脚本(推荐)
May 13 Javascript
js实现简易拖拽的示例
Oct 26 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实现蜘蛛访问日志统计
2013/07/05 PHP
再谈PHP中单双引号的区别详解
2016/06/12 PHP
PHP和MYSQL实现分页导航思路详解
2017/04/11 PHP
javascript flash下fromCharCode和charCodeAt方法使用说明
2008/01/12 Javascript
js 上传图片预览问题
2010/12/06 Javascript
JS 自定义带默认值的函数
2011/07/21 Javascript
js写的方法实现上传图片之后查看大图
2014/03/05 Javascript
javascript中callee与caller的区别分析
2015/04/20 Javascript
深入分析node.js的异步API和其局限性
2016/09/05 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
2016/12/01 Javascript
详解webpack和webpack-simple中如何引入css文件
2017/06/28 Javascript
js禁止浏览器页面后退功能的实例(推荐)
2017/09/01 Javascript
基于vue框架手写一个notify插件实现通知功能的方法
2019/03/31 Javascript
JS块级作用域和私有变量实例分析
2019/05/11 Javascript
在vue中动态添加class类进行显示隐藏实例
2019/11/09 Javascript
如何解决vue在ios微信&quot;复制链接&quot;功能问题
2020/03/26 Javascript
Vue2.0 ES6语法降级ES5的操作
2020/10/30 Javascript
详细解析Python中的变量的数据类型
2015/05/13 Python
关于Python正则表达式 findall函数问题详解
2018/03/22 Python
python sys,os,time模块的使用(包括时间格式的各种转换)
2018/04/27 Python
python破解zip加密文件的方法
2018/05/31 Python
python中多层嵌套列表的拆分方法
2018/07/02 Python
Python-接口开发入门解析
2019/08/01 Python
python数据分析工具之 matplotlib详解
2020/04/09 Python
使用placeholder属性设置input文本框的提示信息
2020/02/19 HTML / CSS
美国背景检查、公共记录和人物搜索网站:BeenVerified
2018/02/25 全球购物
吉力贝官方网站:Jelly Belly
2019/03/11 全球购物
BannerBuzz加拿大:在线定制横幅印刷、广告和标志
2020/03/10 全球购物
个人实用的自我评价范文
2013/11/23 职场文书
班级德育工作实施方案
2014/02/21 职场文书
车辆转让协议书
2014/04/15 职场文书
物流管理专业求职信
2014/05/29 职场文书
大学军训通讯稿(2016最新版)
2015/12/21 职场文书
解决Go gorm踩过的坑
2021/04/30 Golang
Python实现的扫码工具居然这么好用!
2021/06/07 Python
MySQL系列之四 SQL语法
2021/07/02 MySQL