详解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插件 大家可以收藏一下
Feb 07 Javascript
js 回车提交表单两种实现方法
Dec 31 Javascript
特殊情况下如何获取span里面的值
May 20 Javascript
js简单实现调整网页字体大小的方法
Jul 23 Javascript
JS常见算法详解
Feb 28 Javascript
vue-cli脚手架config目录下index.js配置文件的方法
Mar 13 Javascript
vue实现2048小游戏功能思路详解
May 09 Javascript
快速解决vue在ios端下点击响应延时的问题
Aug 27 Javascript
迅速了解一下ES10中Object.fromEntries的用法使用
Mar 05 Javascript
Vue.js watch监视属性知识点总结
Nov 11 Javascript
JavaScript如何使用插值实现图像渐变
Jun 28 Javascript
JavaScript 防盗链的原理以及破解方法
Dec 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
Laravel中扩展Memcached缓存驱动实现使用阿里云OCS缓存
2015/02/10 PHP
检测codeigniter脚本消耗内存情况的方法
2015/03/21 PHP
php使用SAE原生Mail类实现各种类型邮件发送的方法
2016/10/10 PHP
JS 操作符整理[推荐收藏]
2011/11/15 Javascript
JavaScript prototype属性深入介绍
2012/11/27 Javascript
javascript图片滑动效果实现
2021/01/28 Javascript
Node.js连接postgreSQL并进行数据操作
2016/12/18 Javascript
利用imgareaselect辅助后台实现图片上传裁剪
2017/03/02 Javascript
详解VueJs前后端分离跨域问题
2017/05/24 Javascript
VeeValidate在vue项目里表单校验应用案例
2018/05/09 Javascript
在vue项目中集成graphql(vue-ApolloClient)
2018/09/08 Javascript
Vue项目history模式下微信分享爬坑总结
2019/03/29 Javascript
配置一个vue3.0项目的完整步骤
2019/04/26 Javascript
vue路由 遍历生成复数router-link的例子
2019/10/30 Javascript
Python的Django中django-userena组件的简单使用教程
2015/05/30 Python
Python的迭代器和生成器
2015/07/29 Python
Python方法的延迟加载的示例代码
2017/12/18 Python
使用tensorflow实现线性回归
2018/09/08 Python
Python 实现王者荣耀中的敏感词过滤示例
2019/01/21 Python
python3.6+django2.0+mysql搭建网站过程详解
2019/07/24 Python
python获取array中指定元素的示例
2019/11/26 Python
python cookie反爬处理的实现
2020/11/01 Python
Space NK美国站:英国高端美妆护肤商城
2017/05/22 全球购物
Kivari官网:在线购买波西米亚服装
2018/10/29 全球购物
世界上最全面的草药补充剂和顶级品牌维生素网站:HerbsPro
2019/01/20 全球购物
Zavvi西班牙:电子游戏、极客服装、Blu-ray、Funko Pop等
2019/05/03 全球购物
保加利亚手表、香水、化妆品和珠宝购物网站:Brasty.bg
2020/04/22 全球购物
会计专业自荐信范文
2013/12/02 职场文书
松材线虫病防治方案
2014/06/15 职场文书
学习雷锋标语
2014/06/25 职场文书
模具专业求职信
2014/06/26 职场文书
中国在我心中演讲稿
2014/09/13 职场文书
离婚起诉书范文2016
2015/11/26 职场文书
python获取对象信息的实例详解
2021/07/07 Python
Unicode中的CJK(中日韩统一表意文字)字符小结
2021/12/06 HTML / CSS
Spring Bean是如何初始化的详解
2022/03/22 Java/Android