详解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文本框(input textare)事件绑定方法教程
Apr 24 Javascript
轻量级网页遮罩层jQuery插件用法实例
Jul 31 Javascript
js下拉选择框与输入框联动实现添加选中值到输入框的方法
Aug 17 Javascript
JavaScript学习笔记之取数组中最大值和最小值
Mar 23 Javascript
微信小程序 倒计时组件实现代码
Oct 24 Javascript
微信小程序 require机制详解及实例代码
Dec 14 Javascript
easyUI实现类似搜索框关键词自动提示功能示例代码
Dec 27 Javascript
Vuejs 单文件组件实例详解
Feb 09 Javascript
jQuery实现的上传图片本地预览效果简单示例
Mar 29 jQuery
jQuery实现图片简单轮播功能示例
Aug 13 jQuery
使用RxJS更优雅地进行定时请求详析
Jun 02 Javascript
解决Layui中layer报错的问题
Sep 03 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 静态化实现代码
2009/03/20 PHP
PHP设置一边执行一边输出结果的代码
2013/09/30 PHP
支持中文的PHP按字符串长度分割成数组代码
2015/05/17 PHP
PHP一个简单的无需刷新爬虫
2019/01/05 PHP
html+js实现动态显示本地时间
2013/09/21 Javascript
input标签内容改变的触发事件介绍
2014/06/18 Javascript
prototype与__proto__区别详细介绍
2017/01/09 Javascript
JS遍历对象属性的方法示例
2017/01/10 Javascript
Angular.JS实现无限级的联动菜单(使用demo)
2017/02/08 Javascript
浅析JavaScript中var that=this
2017/02/17 Javascript
浅谈regExp的test方法取得的值变化的原因及处理方法
2017/03/01 Javascript
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
2018/05/05 Javascript
Js中将Long转换成日期格式的实现方法
2018/06/05 Javascript
jquery实现垂直手风琴菜单
2020/03/04 jQuery
微信小程序手动添加收货地址省市区联动
2020/05/18 Javascript
vue 函数调用加括号与不加括号的区别
2020/10/29 Javascript
基于VUE实现简单的学生信息管理系统
2021/01/13 Vue.js
[02:40]DOTA2英雄基础教程 先知
2013/11/29 DOTA
[04:53]DOTA2英雄基础教程 祈求者
2014/01/03 DOTA
[38:42]完美世界DOTA2联赛循环赛 Matador vs Forest BO2第二场 11.05
2020/11/05 DOTA
[54:15]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第二场2月1日
2021/03/11 DOTA
python用来获得图片exif信息的库实例分析
2015/03/16 Python
python中安装模块包版本冲突问题的解决
2017/05/02 Python
python实现kNN算法
2017/12/20 Python
对numpy和pandas中数组的合并和拆分详解
2018/04/11 Python
ActiveMQ:使用Python访问ActiveMQ的方法
2019/01/30 Python
python中的django是做什么的
2020/07/31 Python
实现Python3数组旋转的3种算法实例
2020/09/16 Python
应届大学生自荐信格式
2013/09/21 职场文书
大学生职业生涯规划书的基本内容
2014/01/06 职场文书
公积金转移接收函
2014/01/11 职场文书
英语教学随笔感言
2014/02/20 职场文书
《分一分》教学反思
2014/04/13 职场文书
认错检讨书
2014/10/02 职场文书
这样写python注释让代码更加的优雅
2021/06/02 Python
Python Pandas数据分析之iloc和loc的用法详解
2021/11/11 Python